Nginx Proxy Manager: รวมหลายแอปไว้หลัง HTTPS บนเครื่องเดียว

ติดตั้ง Nginx Proxy Manager ด้วย Docker Compose ให้หลายแอปบนเซิร์ฟเวอร์เดียวใช้โดเมนและ SSL ฟรีจาก Let's Encrypt ผ่านหน้าเว็บ พร้อมซ่อนพอร์ตแอดมิน 81

โดย ทีมงาน THAI DATA CLOUD อัปเดต อ่าน 12 นาที

แชร์FacebookXLINELinkedIn
Nginx Proxy Manager — Nginx Proxy Manager: รวมหลายแอปไว้หลัง HTTPS บนเครื่องเดียว
Nginx Proxy Manager: รวมหลายแอปไว้หลัง HTTPS บนเครื่องเดียว

คำตอบสั้น ๆ: ติดตั้ง Nginx Proxy Manager ด้วย Docker Compose ให้หลายแอปบนเซิร์ฟเวอร์เดียวใช้โดเมนและ SSL ฟรีจาก Let's Encrypt ผ่านหน้าเว็บ พร้อมซ่อนพอร์ตแอดมิน 81

คู่มือนี้อธิบาย Nginx Proxy Manager ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย

Nginx Proxy Manager (NPM) คือ reverse proxy ที่มีหน้าเว็บสำหรับจัดการ ทำหน้าที่รับทราฟฟิก HTTP และ HTTPS ทั้งหมดของเซิร์ฟเวอร์ที่พอร์ต 80 และ 443 แล้วส่งต่อไปยังแอปแต่ละตัวตามชื่อโดเมน พร้อมขอและต่ออายุใบรับรอง SSL ฟรีจาก Let's Encrypt ให้อัตโนมัติ เหมาะกับทีมที่รันหลายแอปบน Cloud VPS เครื่องเดียว เช่น Wiki, ระบบจัดการรหัสผ่าน หรือ Git Server แต่ไม่อยากเขียนไฟล์คอนฟิก Nginx เองทีละไฟล์

เมื่อทำตามคู่มือนี้จบ คุณจะมี Nginx Proxy Manager ที่รันด้วย Docker Compose, เครือข่าย Docker ชื่อ proxy ที่แอปอื่นมาต่อได้โดยไม่ต้องเปิดพอร์ตของแอปออกอินเทอร์เน็ต, Proxy Host แรกที่ใช้ HTTPS แล้ว และหน้าแอดมินพอร์ต 81 ที่เข้าได้ผ่าน SSH tunnel เท่านั้น คู่มือแอปอื่นในหมวด Cloud VPS App Plus ชุดนี้ใช้โครงสร้างนี้เป็นฐานทั้งหมด

สิ่งที่ต้องเตรียม

  • Cloud VPS หรือ Cloud Server ที่ใช้ Ubuntu 24.04 และติดตั้ง Docker Engine กับ Compose plugin แล้ว (ดู ติดตั้ง Docker และ Docker Compose บน Ubuntu) ผู้ใช้อยู่ในกลุ่ม docker หรือใส่ sudo หน้าคำสั่ง
  • ขนาดเครื่อง: ตัว NPM ใช้ทรัพยากรน้อย 1 vCPU และ RAM 1 GB ก็พอ แต่ให้คิดรวมแอปที่จะวางหลังมันด้วย ตัวเลขนี้เป็นจุดเริ่มต้นโดยประมาณ ปรับตามการใช้งานจริง
  • โดเมนหรือซับโดเมนที่ทำ A record ชี้มาที่ IP สาธารณะของเซิร์ฟเวอร์แล้ว เช่น test.example.com → 203.0.113.10
  • พอร์ต 80 และ 443 ต้องว่าง ไม่มี Nginx หรือ Apache บนโฮสต์ใช้อยู่ ตรวจด้วย sudo ss -tlnp | grep -E ':(80|443) '
  • ไฟร์วอลล์ระดับคลาวด์อนุญาต TCP 22, 80 และ 443

ถ้าเครื่องมี Nginx บนโฮสต์ที่ตั้งค่าไว้แล้ว ให้ใช้ server block ตามคู่มือ ตั้งค่า Nginx Server Block สำหรับหลายเว็บไซต์ ต่อไป อย่ารันสองตัวแย่งพอร์ต 80/443 กัน

แผนภาพผู้ใช้เข้า HTTPS พอร์ต 443 ผ่าน Nginx Proxy Manager แล้วส่งต่อไปยังคอนเทนเนอร์แอปในเครือข่าย proxy
NPM รับทุกคำขอที่ 80/443 แล้วส่งต่อตามโดเมนไปยังคอนเทนเนอร์ที่ไม่ได้เปิดพอร์ตออกนอกเครื่อง

ขั้นตอนที่ 1: สร้างเครือข่าย proxy และโฟลเดอร์งาน

สร้างเครือข่าย Docker ที่ใช้ร่วมกันก่อน แอปทุกตัวที่ต่อเข้าเครือข่ายนี้ Nginx Proxy Manager จะเรียกหาได้ด้วยชื่อคอนเทนเนอร์ จึงไม่ต้อง publish พอร์ตของแอปออกไปที่โฮสต์เลย

docker network create proxy
sudo mkdir -p /opt/npm
sudo chown $USER: /opt/npm
cd /opt/npm

คำสั่ง docker network ls ควรแสดงเครือข่ายชื่อ proxy ชนิด bridge

ขั้นตอนที่ 2: เขียนไฟล์ compose.yaml ของ Nginx Proxy Manager

สร้างไฟล์ /opt/npm/compose.yaml ด้วย nano compose.yaml แล้ววางเนื้อหานี้

services:
  npm:
    image: jc21/nginx-proxy-manager:2
    container_name: npm
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "127.0.0.1:81:81"   # หน้าแอดมิน เปิดเฉพาะในเครื่อง
    environment:
      TZ: Asia/Bangkok
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    networks:
      - proxy

networks:
  proxy:
    external: true

แท็ก 2 หมายถึงรุ่นล่าสุดในสาย 2.x จึงได้อัปเดตแก้บั๊กโดยไม่กระโดดข้ามเวอร์ชันหลักเอง ส่วน 127.0.0.1:81:81 สำคัญมาก เพราะ Docker เขียนกฎ iptables ของตัวเองและข้ามกฎของ UFW ไป การสั่ง ufw deny 81 จึงไม่ได้ปิดพอร์ตที่ Docker publish ไว้ วิธีที่ได้ผลคือผูกพอร์ตไว้กับ 127.0.0.1 ตั้งแต่แรก

docker compose up -d
docker compose logs -f npm

รอจนล็อกนิ่งและไม่มีข้อความ error แล้วกด Ctrl+C ออกจากการดูล็อก (คอนเทนเนอร์ยังทำงานต่อ)

ขั้นตอนที่ 3: เข้าหน้าแอดมินผ่าน SSH tunnel และสร้างบัญชีแรก

บนเครื่องคอมพิวเตอร์ของคุณ เปิด tunnel ไปที่พอร์ต 81 ของเซิร์ฟเวอร์ แล้วเปิดเบราว์เซอร์ไปที่ http://localhost:8181

ssh -L 8181:127.0.0.1:81 [email protected]

รุ่นปัจจุบันจะแสดงหน้า Welcome! พร้อมข้อความ Get started by creating your admin account ให้กรอกชื่อ อีเมล และรหัสผ่านที่ยาวและไม่ซ้ำกับระบบอื่น (รุ่นเก่าบางรุ่นใช้บัญชีเริ่มต้น [email protected] / changeme แล้วบังคับให้เปลี่ยนทันทีหลังล็อกอิน) จากนั้นเปิด Two-Factor Authentication จากเมนูผู้ใช้ เพราะบัญชีนี้ควบคุมใบรับรองและเส้นทางของทุกแอป

ขั้นตอนที่ 4: เพิ่ม Proxy Host แรกพร้อม SSL

ทดสอบด้วยแอปตัวอย่างขนาดเล็ก traefik/whoami ที่ตอบกลับข้อมูลของคำขอ ต่อเข้าเครือข่าย proxy โดยไม่ publish พอร์ต

docker run -d --name whoami --network proxy --restart unless-stopped traefik/whoami

ในหน้า Nginx Proxy Manager ไปที่ Hosts → Proxy Hosts → Add Proxy Host แล้วกรอก

  • Domain Names: test.example.com
  • Scheme: http และ Forward Hostname / IP: whoami (ชื่อคอนเทนเนอร์) Forward Port: 80 (พอร์ตภายในคอนเทนเนอร์)
  • เปิด Block Common Exploits และเปิด Websockets Support เมื่อแอปใช้ WebSocket
  • แท็บ SSL: เลือก Request a new Certificate (Let's Encrypt) แล้วเปิด Force SSL และ HTTP/2 Support
ภาพจำลองหน้าต่าง Add Proxy Host ของ Nginx Proxy Manager กรอกโดเมน ชื่อคอนเทนเนอร์ whoami และพอร์ต 80
Forward Hostname ใช้ชื่อคอนเทนเนอร์ในเครือข่าย proxy ไม่ใช่ 127.0.0.1 (ภาพจำลอง)

กด Save ระบบจะขอใบรับรองให้ภายในไม่กี่วินาที ห้ามใส่ 127.0.0.1 ในช่อง Forward Hostname เพราะภายในคอนเทนเนอร์ของ NPM ที่อยู่นี้หมายถึงตัว NPM เอง ไม่ใช่โฮสต์ เปิด HSTS Enabled ภายหลังเมื่อมั่นใจว่าโดเมนนี้จะใช้ HTTPS ตลอดไป

ขั้นตอนที่ 5: จำกัดแอปภายในด้วย Access List

แอปที่ใช้เฉพาะพนักงาน เช่น หน้าแอดมินหรือแดชบอร์ด ควรจำกัด IP ต้นทาง ไปที่ Access Lists → Add Access List ตั้งชื่อ เช่น office-only แล้วในส่วน Rules เพิ่ม Allow 198.51.100.0/24 (IP สำนักงานหรือ VPN) ระบบจะเติมกฎ deny all ไว้ท้ายสุดให้เอง จะเพิ่มชื่อผู้ใช้และรหัสผ่าน (Basic Auth) ในส่วน Authorization ด้วยก็ได้

จากนั้นแก้ Proxy Host ของแอปนั้น เลือก Access List เป็น office-only ข้อควรระวังคือแอปที่มีแอปมือถือหรือ API ของตัวเอง เช่น ระบบจัดการรหัสผ่าน จะใช้งานไม่ได้ถ้าครอบด้วย Basic Auth ให้ใช้เฉพาะกฎ IP หรือไม่ใช้ Access List กับแอปแบบนั้น

ขั้นตอนที่ 6: ปิดช่องโหว่ที่เหลือ สำรองข้อมูล และอัปเดต

เปิด UFW ให้เหลือเฉพาะพอร์ตที่จำเป็นตามคู่มือ ตั้งค่า Firewall ด้วย UFW บน Ubuntu แล้วไปที่ Settings → Default Site เลือก No Response (444) เพื่อให้บอตที่ยิงเข้ามาที่ IP ตรง ๆ ไม่ได้รับหน้าใด ๆ กลับไป

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

ข้อมูลสำคัญทั้งหมดอยู่ใน data/ (ฐานข้อมูล SQLite และคอนฟิก) และ letsencrypt/ (ใบรับรอง) สำรองโดยหยุดคอนเทนเนอร์สั้น ๆ เพื่อไม่ให้ไฟล์ฐานข้อมูลอยู่ระหว่างเขียน แล้วนำไฟล์ไปเก็บนอกเครื่อง

cd /opt/npm
docker compose stop
sudo tar czf /var/backups/npm-$(date +%F).tar.gz data letsencrypt
docker compose start

อัปเดตเป็นรุ่นล่าสุดในสาย 2.x ด้วย docker compose pull && docker compose up -d แนะนำให้สำรองก่อนทุกครั้ง

ผลคำสั่ง docker compose ps ของ Nginx Proxy Manager ที่พอร์ต 81 ผูกกับ 127.0.0.1 และ curl ที่ได้ HTTP/2 200
พอร์ต 81 ต้องผูกกับ 127.0.0.1 ส่วน 80/443 เปิดสู่ภายนอก และโดเมนทดสอบตอบ HTTPS ได้

ตรวจสอบว่า Nginx Proxy Manager ทำงานถูกต้อง

รัน docker compose ps คอลัมน์ PORTS ต้องเห็น 81 ผูกกับ 127.0.0.1 เท่านั้น และ curl -I https://test.example.com จากเครื่องภายนอกต้องได้ HTTP/2 200 ลองเรียก http://203.0.113.10:81 จากภายนอก ต้องเชื่อมต่อไม่ได้

ปัญหาที่พบบ่อยเกี่ยวกับ Nginx Proxy Manager

ขอใบรับรอง Let's Encrypt แล้วขึ้น Internal Error ต้องแก้อย่างไร?

สาเหตุเกือบทั้งหมดคือ Let's Encrypt เข้าพอร์ต 80 ของโดเมนไม่ได้ ตรวจว่า dig +short test.example.com ได้ IP ของเซิร์ฟเวอร์จริง ไฟร์วอลล์ระดับคลาวด์เปิด TCP 80 และถ้าใช้ Cloudflare ให้ปิดโหมด Proxy (เมฆสีส้ม) ชั่วคราวหรือเปลี่ยนไปใช้ Use DNS Challenge หากลองผิดหลายครั้งติดกัน ให้รอสักพักเพราะ Let's Encrypt จำกัดจำนวนคำขอต่อโดเมน

เปิดโดเมนแล้วได้ 502 Bad Gateway เกิดจากอะไร?

NPM ติดต่อแอปปลายทางไม่ได้ ตรวจว่าคอนเทนเนอร์ของแอปต่อเข้าเครือข่าย proxy แล้วด้วย docker network inspect proxy, ช่อง Forward Hostname เป็นชื่อคอนเทนเนอร์ (ไม่ใช่ 127.0.0.1) และ Forward Port เป็นพอร์ตภายในคอนเทนเนอร์ ไม่ใช่พอร์ตที่ publish บนโฮสต์ แอปบางตัวต้องใช้เวลาเริ่มระบบหลายนาที ให้ดู docker compose logs ของแอปประกอบ

ปิดพอร์ต 81 ใน UFW แล้ว ทำไมยังเข้าหน้าแอดมินจากภายนอกได้?

เพราะพอร์ตที่ Docker publish ถูกจัดการด้วยกฎ iptables ของ Docker ซึ่งทำงานก่อนกฎของ UFW แก้ที่ compose.yaml ให้เป็น 127.0.0.1:81:81 แล้วรัน docker compose up -d อีกครั้ง หรือปิดพอร์ตที่ไฟร์วอลล์ระดับคลาวด์ รายละเอียดดูได้จาก เอกสาร Docker เรื่อง packet filtering

แอปที่อยู่หลัง Nginx Proxy Manager หน้าค้างหรือหลุดการเชื่อมต่อบ่อย?

แอปที่อัปเดตหน้าจอแบบเรียลไทม์ เช่น แชท ระบบ CI หรือระบบจัดการรหัสผ่าน ต้องเปิด Websockets Support ใน Proxy Host นั้น ถ้าเป็นงานที่ประมวลผลนาน ให้เพิ่ม proxy_read_timeout 300s; ในแท็บ Advanced ของ Proxy Host ดูตัวเลือกเพิ่มเติมได้ที่ คู่มือทางการของ Nginx Proxy Manager

เช็กลิสต์ความปลอดภัย Nginx Proxy Manager เช่น ผูกพอร์ต 81 กับ localhost เปิด 2FA และตั้ง Default Site เป็น 444
ตรวจทุกข้อหลังติดตั้ง และทุกครั้งที่เพิ่มแอปใหม่เข้าเครือข่าย proxy

หากต้องการเซิร์ฟเวอร์สำหรับรันหลายแอปไว้หลัง Nginx Proxy Manager ดูแพ็กเกจ Cloud VPS App Plus หรือ ติดต่อทีมงาน THAI DATA CLOUD เพื่อช่วยออกแบบโครงสร้างเครื่องและไฟร์วอลล์ให้เหมาะกับองค์กรของคุณ

สรุปขั้นตอน Nginx Proxy Manager

ทบทวน Nginx Proxy Manager ทั้งหมดตามลำดับ ก่อนนำไปใช้กับระบบจริง

  1. สร้างเครือข่าย proxy และโฟลเดอร์งาน
  2. เขียนไฟล์ compose.yaml ของ Nginx Proxy Manager
  3. เข้าหน้าแอดมินผ่าน SSH tunnel และสร้างบัญชีแรก
  4. เพิ่ม Proxy Host แรกพร้อม SSL
  5. จำกัดแอปภายในด้วย Access List
  6. ปิดช่องโหว่ที่เหลือ สำรองข้อมูล และอัปเดต

เมื่อทำครบทุกข้อแล้ว Nginx Proxy Manager จะพร้อมใช้งาน หากผลลัพธ์ไม่เป็นไปตามที่คาด ให้ย้อนกลับไปดูหัวข้อปัญหาที่พบบ่อยด้านบน ซึ่งรวบรวมกรณีที่พบจริงจากการใช้งาน Nginx Proxy Manager ไว้แล้ว

อ่านเพิ่มเติมเกี่ยวกับ Nginx Proxy Manager

แชร์FacebookXLINELinkedIn

มีคำถามเรื่องบริการ? ติดต่อทีมงาน