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