
ถ้าคุณรันหลาย Service บน VPS เดียวกัน ไม่ว่าจะเป็น WordPress, Node.js, Grafana หรือ Portainer คุณคงรู้ดีว่าปัญหาหลักคือการจัดการ Port และ SSL นั้นยุ่งยากและต้องเขียน Nginx config เองทุกครั้ง Nginx Proxy Manager (NPM) คือเครื่องมือที่แก้ปัญหานี้ได้อย่างตรงจุด ด้วย Web UI ที่สวยงามและใช้งานง่าย ทำให้คุณตั้ง Reverse Proxy และออก SSL Certificate ผ่าน Let's Encrypt ได้ในไม่กี่คลิก โดยไม่ต้องแตะ Nginx config แม้แต่บรรทัดเดียว
Nginx Proxy Manager คืออะไร
Nginx Proxy Manager คือ Web Application ที่ทำหน้าที่เป็น Frontend สำหรับจัดการ Nginx Reverse Proxy ผ่าน UI แทนที่จะต้องเขียน /etc/nginx/sites-available/mysite.conf ด้วยมือ คุณเพียงแค่กรอกข้อมูล Domain Name, Forward Hostname และ Port ใน UI แล้วกด Save ระบบจะสร้าง Nginx config และออก SSL ให้อัตโนมัติ
NPM รันผ่าน Docker
NPM ถูก Distribute เป็น Docker Image ทำให้ติดตั้งและ Upgrade ง่ายมาก ไม่กระทบกับ Package อื่นบน Server และสามารถลบออกได้สะอาดโดยไม่มีไฟล์ค้างในระบบ
Feature หลักของ Nginx Proxy Manager
- Proxy Hosts: Reverse Proxy ให้ domain ชี้ไปยัง service ที่ต้องการ พร้อม SSL อัตโนมัติ
- Free SSL Certificates: ออก Let's Encrypt cert อัตโนมัติ รวมถึง Wildcard cert ผ่าน DNS Challenge
- Access Lists: จำกัด IP หรือเพิ่ม HTTP Basic Auth ให้แต่ละ Proxy Host
- Redirection Hosts: Redirect domain หนึ่งไปยังอีก domain (301/302)
- Streams: Forward TCP/UDP traffic สำหรับ non-HTTP protocol
- Custom Nginx Config: เพิ่ม Nginx directive เพิ่มเติมได้ผ่าน Advanced tab
เปรียบเทียบ NPM vs ตัวเลือกอื่น
- NPM vs Nginx ด้วยมือ: NPM ง่ายและเร็วกว่ามากสำหรับผู้ที่ไม่ถนัด Nginx config แต่ Nginx ด้วยมือ flexible กว่าสำหรับ Edge Case ที่ซับซ้อน
- NPM vs Traefik: Traefik ล้ำกว่าสำหรับ Kubernetes/Microservices environment ที่ config เปลี่ยนบ่อย แต่ NPM ใช้งานง่ายกว่าและเหมาะกับ VPS ทั่วไป
- NPM vs Caddy: Caddy มี Automatic HTTPS เช่นกัน แต่ NPM มี UI ที่ทำให้ Non-developer ใช้งานได้ง่ายกว่า
เหมาะสำหรับ: VPS ที่รันหลาย Service โดยไม่อยากเขียน Nginx config ด้วยมือ, มือใหม่ที่ต้องการ UI ช่วย, หรือทีมที่ต้องการ Delegate การจัดการ Proxy ให้คนอื่นโดยไม่ต้อง SSH เข้า Server
Prerequisites ก่อนติดตั้ง
ก่อนเริ่มติดตั้ง Nginx Proxy Manager ตรวจสอบให้แน่ใจว่าคุณมีสิ่งต่อไปนี้ครบถ้วน
- VPS Ubuntu 22.04 หรือ 20.04 — รองรับทั้งสองเวอร์ชัน
- Docker และ Docker Compose — ต้องติดตั้งไว้ก่อน (ดูวิธีติดตั้งได้ที่ บทความ Docker บน VPS)
- โดเมนที่ DNS ชี้มาที่ IP ของ VPS แล้ว — ตั้ง A Record ให้ชี้มาที่ IP ของคุณ และรอ DNS Propagate ก่อนจะขอ SSL cert
- Root หรือ Sudo Access บน Server
- RAM อย่างน้อย 512MB (แนะนำ 1GB ขึ้นไป)
เปิด Port ใน UFW Firewall
NPM ต้องการ Port 3 ตัว ได้แก่ Port 80 (HTTP), 443 (HTTPS) และ 81 (NPM Web UI) ตรวจสอบและเปิด Port เหล่านี้ด้วยคำสั่ง
# เปิด Port 80 (HTTP) และ 443 (HTTPS) — จำเป็นสำหรับ Reverse Proxy และ SSL ufw allow 80/tcp ufw allow 443/tcp # เปิด Port 81 สำหรับ NPM Web UI (ชั่วคราว — แนะนำให้ปิดทีหลัง) ufw allow 81/tcp # ตรวจสอบสถานะ ufw status numbered
Security Note: Port 81 ควรเปิดเฉพาะช่วง Setup และ Maintenance เท่านั้น หลัง Setup เสร็จควร Block Port 81 จาก Public Internet แล้วใช้ SSH Tunnel แทน (อธิบายในหัวข้อ Security Hardening)
ติดตั้ง Nginx Proxy Manager ด้วย Docker Compose
วิธีที่แนะนำในการติดตั้ง NPM คือผ่าน Docker Compose ซึ่งทำให้ Manage ง่ายและ Reproducible
ขั้นตอนการติดตั้ง
-
สร้าง Directory สำหรับ NPM
mkdir -p ~/npm && cd ~/npm
-
สร้างไฟล์ docker-compose.yml
สร้างไฟล์
docker-compose.ymlใน directory ที่เพิ่งสร้างnano ~/npm/docker-compose.yml
แล้วใส่เนื้อหาต่อไปนี้ลงในไฟล์ (เปลี่ยน Password ให้แข็งแกร่ง)
version: '3.8' services: app: image: 'jc21/nginx-proxy-manager:latest' restart: unless-stopped ports: - '80:80' - '443:443' - '81:81' volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt db: image: 'jc21/mariadb-aria:latest' restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: 'npm_root_pw_changeme' MYSQL_DATABASE: 'npm' MYSQL_USER: 'npm' MYSQL_PASSWORD: 'npm_pw_changeme' volumes: - ./mysql:/var/lib/mysql -
รัน Docker Compose
cd ~/npm && docker compose up -d
Docker จะดึง Image ลงมาและเริ่ม Container ทั้งสองตัว (app และ db) ครั้งแรกอาจใช้เวลา 1–2 นาที
-
ตรวจสอบว่า Container รันอยู่
cd ~/npm && docker compose ps
ควรเห็น Container ทั้งสองตัวมีสถานะ
Up -
เข้า Web UI ครั้งแรก
เปิด Browser แล้วไปที่
http://YOUR_VPS_IP:81(แทนที่YOUR_VPS_IPด้วย IP จริงของ VPS คุณ)
หมายเหตุ: ถ้ามี Nginx หรือ Apache รันอยู่บน Port 80/443 อยู่แล้ว ต้องหยุด Service เหล่านั้นก่อน ไม่เช่นนั้น Docker จะ Bind Port ไม่ได้ ใช้คำสั่ง systemctl stop nginx หรือ systemctl stop apache2 แล้ว Disable ด้วย systemctl disable nginx
First Login และเปลี่ยน Password
เมื่อเข้า Web UI ที่ Port 81 ครั้งแรก ระบบจะแสดงหน้า Login ให้ใช้ข้อมูลเริ่มต้นดังนี้
- Email:
[email protected] - Password:
changeme
หลัง Login สำเร็จ NPM จะบังคับให้เปลี่ยน Email และ Password ทันทีผ่าน Dialog ที่ปรากฏขึ้นมา ห้ามข้ามขั้นตอนนี้
แนะนำสำหรับ First Login
- ใส่ Email จริงของคุณ — ใช้สำหรับรับแจ้งเตือน SSL Certificate ใกล้หมดอายุ
- ตั้ง Password ที่แข็งแกร่ง — อย่างน้อย 16 ตัวอักษร ผสมตัวพิมพ์ใหญ่ ตัวเลข และสัญลักษณ์
- หลังเปลี่ยน Credential แล้ว NPM จะ Logout อัตโนมัติ ให้ Login ด้วย Credential ใหม่
เพิ่ม Proxy Host ตัวแรก
Proxy Host คือการ Map Domain ให้ชี้ไปยัง Service ที่รันอยู่บน Port ใด Port หนึ่งบน Server (หรือ Container ใน Network เดียวกัน) พร้อมกับออก SSL Certificate ให้อัตโนมัติ
วิธีเพิ่ม Proxy Host
-
ไปที่ Hosts → Proxy Hosts → Add Proxy Host
คลิกที่เมนู Hosts ด้านบน แล้วเลือก Proxy Hosts จากนั้นคลิกปุ่ม Add Proxy Host สีเขียวด้านขวา
-
กรอกข้อมูล Details tab
- Domain Names: ใส่โดเมนของคุณ เช่น
app.example.com(กด Enter หลังพิมพ์) - Scheme: เลือก
http(สำหรับ Service ที่รันด้วย HTTP ปกติ) - Forward Hostname / IP: ใส่ IP หรือ Container name ของ Service (เช่น
localhostหรือwordpressถ้าอยู่ใน Docker network เดียวกัน) - Forward Port: Port ที่ Service ฟังอยู่ เช่น
8080 - Block Common Exploits: เปิดไว้ (แนะนำ)
- Websockets Support: เปิดถ้า Service ใช้ WebSocket (เช่น Socket.io, Grafana Live)
- Domain Names: ใส่โดเมนของคุณ เช่น
-
ตั้งค่า SSL ใน tab SSL
- คลิก Tab SSL
- เลือก Request a new SSL Certificate จาก Dropdown
- เปิด Force SSL — บังคับ Redirect HTTP → HTTPS
- เปิด HTTP/2 Support — ช่วยความเร็ว
- ใส่ Email Address สำหรับ Let's Encrypt notification
- ติ๊ก I Agree to the Let's Encrypt Terms of Service
-
กด Save
NPM จะสร้าง Nginx config และขอ SSL Certificate จาก Let's Encrypt ทันที กระบวนการนี้ใช้เวลาประมาณ 15–30 วินาที หลังจากนั้น Proxy Host จะมีสถานะ Online สีเขียว
DNS ต้องพร้อมก่อน: ก่อน NPM จะขอ SSL Certificate ได้สำเร็จ DNS ของโดเมนต้องชี้มาที่ IP ของ VPS แล้ว และ Propagate แล้ว (ตรวจสอบที่ dnschecker.org) ถ้า DNS ยังไม่พร้อม SSL จะ Fail และ Proxy Host จะแสดงสถานะ Offline
ตัวอย่างใช้งานจริง: รัน 3 Service บน VPS เดียว
สถานการณ์นี้พบบ่อยมาก: คุณรัน WordPress, Grafana และ Portainer บน VPS เดียว และต้องการให้แต่ละ Service มี Domain ของตัวเองพร้อม SSL โดยไม่ต้องจำ Port
Domain Mapping ที่ต้องการ
blog.example.com→localhost:8080(WordPress)monitor.example.com→localhost:3000(Grafana)docker.example.com→localhost:9000(Portainer)
ขั้นตอนสำหรับ WordPress (Port 8080)
# ใน NPM Web UI Domain Names: blog.example.com Scheme: http Forward Hostname / IP: localhost Forward Port: 8080 Block Common Exploits: ON Websockets Support: OFF SSL: Request new cert, Force SSL ON, HTTP/2 ON
ขั้นตอนสำหรับ Grafana (Port 3000)
# ใน NPM Web UI Domain Names: monitor.example.com Scheme: http Forward Hostname / IP: localhost Forward Port: 3000 Block Common Exploits: ON Websockets Support: ON ← Grafana ใช้ WebSocket สำหรับ Live Dashboard SSL: Request new cert, Force SSL ON, HTTP/2 ON
ขั้นตอนสำหรับ Portainer (Port 9000)
# ใน NPM Web UI Domain Names: docker.example.com Scheme: http Forward Hostname / IP: localhost Forward Port: 9000 Block Common Exploits: ON Websockets Support: ON ← Portainer ใช้ WebSocket SSL: Request new cert, Force SSL ON, HTTP/2 ON
สำคัญมาก: ถ้า NPM และ Service ต่าง ๆ รันอยู่ใน Docker Container ด้วยกัน การใช้ localhost อาจไม่ทำงานเสมอไป เพราะ Container แต่ละตัวมี Network Namespace แยกกัน วิธีที่ถูกต้องคือการใช้ Docker Network ร่วมกัน ดูหัวข้อถัดไป
Docker Network — วิธีที่ถูกต้องสำหรับ Container-to-Container
เมื่อทั้ง NPM และ Services รันใน Docker Container การเชื่อมต่อกันที่ถูกต้องและ Stable ที่สุดคือการใช้ Docker Network ร่วมกัน แล้วใช้ Container Name แทน IP Address หรือ localhost เพราะ Container Name จะไม่เปลี่ยนแม้ Container จะ Restart และ IP เปลี่ยน
สร้าง Custom Docker Network
# สร้าง Network ชื่อ npm_network docker network create npm_network
docker-compose.yml แบบมี Network
แก้ไขไฟล์ ~/npm/docker-compose.yml ให้เพิ่ม Network config
version: '3.8'
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80'
- '443:443'
- '81:81'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
networks:
- npm_network
db:
image: 'jc21/mariadb-aria:latest'
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: 'npm_root_pw_changeme'
MYSQL_DATABASE: 'npm'
MYSQL_USER: 'npm'
MYSQL_PASSWORD: 'npm_pw_changeme'
volumes:
- ./mysql:/var/lib/mysql
networks:
- npm_network
networks:
npm_network:
external: truedocker-compose.yml สำหรับ Service ที่ต้องการ Proxy
Service อื่น (เช่น WordPress) ต้องอยู่ใน Network เดียวกัน
version: '3.8'
services:
wordpress:
image: wordpress:latest
restart: unless-stopped
container_name: wordpress # ชื่อนี้จะใช้เป็น Forward Hostname ใน NPM
environment:
WORDPRESS_DB_HOST: wp_db
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wp_user
WORDPRESS_DB_PASSWORD: wp_pass_changeme
volumes:
- ./wp_data:/var/www/html
networks:
- npm_network # อยู่ใน npm_network เดียวกัน
wp_db:
image: mysql:8.0
restart: unless-stopped
container_name: wp_db
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wp_user
MYSQL_PASSWORD: wp_pass_changeme
MYSQL_ROOT_PASSWORD: root_pass_changeme
volumes:
- ./wp_mysql:/var/lib/mysql
networks:
- npm_network
networks:
npm_network:
external: trueเมื่อทุก Container อยู่ใน npm_network เดียวกัน ในการตั้ง Proxy Host ให้ใช้ Container Name (wordpress) แทน localhost ใน Forward Hostname และ Port 80 (ไม่ใช่ 8080 เพราะ Map Port ใช้สำหรับ Host-to-Container เท่านั้น ภายใน Network Container ใช้ Port ตรง ๆ)
ตรวจสอบ Network
# ดูว่า Container ใดอยู่ใน npm_network บ้าง
docker network inspect npm_network
# ดู Container ทั้งหมดที่รันอยู่
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"SSL Certificate — Let's Encrypt และ Wildcard
NPM จัดการ SSL Certificate ได้ครบถ้วนทั้ง Single Domain และ Wildcard Cert โดยไม่ต้องใช้ Certbot แยกต่างหาก
SSL Certificates Tab
ไปที่เมนู SSL Certificates เพื่อดู Certificate ทั้งหมดที่มีอยู่ รวมถึงวันหมดอายุ NPM จะ Renew Certificate อัตโนมัติก่อนหมดอายุ ไม่ต้องทำอะไรเพิ่มเติม
Wildcard Certificate (*.example.com)
Wildcard Certificate ครอบคลุม Subdomain ทุกตัวของ Domain ด้วย Certificate เดียว เช่น *.example.com ครอบคลุม blog.example.com, monitor.example.com, docker.example.com ทั้งหมด ข้อดีคือไม่ต้องขอ cert แยกสำหรับแต่ละ Subdomain
Wildcard Cert ต้องใช้ DNS Challenge (ไม่ใช่ HTTP Challenge) เพราะต้องพิสูจน์ว่าคุณควบคุม DNS ของ Domain ได้ NPM รองรับ DNS Provider หลายตัว เช่น Cloudflare, Route 53, Namecheap
ขั้นตอน Wildcard Cert ด้วย Cloudflare DNS Challenge
-
ได้รับ Cloudflare API Token
เข้า Cloudflare Dashboard → Profile → API Tokens → Create Token → เลือก Template "Edit zone DNS" แล้วจำกัด Zone เฉพาะ Domain ของคุณ
-
เพิ่ม SSL Certificate ใน NPM
ไปที่ SSL Certificates → Add SSL Certificate → Let's Encrypt
- Domain Names:
*.example.comและexample.com(ใส่ทั้งสองเพื่อครอบคลุม root domain ด้วย) - Use a DNS Challenge: เปิด
- DNS Provider: เลือก Cloudflare
- Credentials File Content: ใส่
dns_cloudflare_api_token = YOUR_CF_API_TOKEN - Propagation Seconds:
120(รอ DNS Propagate 2 นาที)
- Domain Names:
-
กด Save
NPM จะสร้าง TXT Record ใน Cloudflare ผ่าน API เพื่อ Verify Domain แล้วออก Wildcard Certificate
-
นำ Wildcard Cert ไปใช้กับ Proxy Host
เมื่อเพิ่ม Proxy Host ใหม่ ในแท็ป SSL เลือก Wildcard cert ที่สร้างไว้ แทนการขอ cert ใหม่
Auto-Renewal
NPM จัดการ Renew Certificate อัตโนมัติ ไม่ต้องตั้ง Cron Job เพิ่มเติม Let's Encrypt cert มีอายุ 90 วัน NPM จะ Renew ก่อนหมดอายุ 30 วัน
Access List — จำกัดการเข้าถึง
Access List ช่วยให้คุณจำกัดว่าใครสามารถเข้าถึง Proxy Host ได้บ้าง มีสองรูปแบบหลัก: IP Whitelist และ HTTP Basic Authentication
สร้าง Access List
ไปที่เมนู Access Lists → Add Access List
รูปแบบที่ 1: IP Whitelist
จำกัดการเข้าถึงเฉพาะ IP ที่กำหนด เหมาะสำหรับ Internal Tools เช่น Admin Panel
# ใน Access List Configuration Name: "My Home IP" Allow: 203.0.113.10 # IP บ้านของคุณ Allow: 10.0.0.0/8 # IP Range ของ Internal Network Deny: All (ติ๊กที่ "Satisfy any" = OFF เพื่อให้เป็น Whitelist)
รูปแบบที่ 2: HTTP Basic Authentication
เพิ่ม Username/Password ให้ Service ที่ไม่มี Login ในตัวเอง เช่น Netdata Dashboard หรือ Simple Web App
# ใน Access List — Tab "Authorization" เพิ่ม Username และ Password ได้หลายคู่ NPM จะสร้าง htpasswd ให้อัตโนมัติ
นำ Access List ไปใช้กับ Proxy Host
เมื่อสร้าง Access List แล้ว ไปแก้ไข Proxy Host แล้วเลือก Access List ที่ต้องการในฟิลด์ Access List ใน Details tab
Custom Nginx Config (Advanced)
แต่ละ Proxy Host มี Advanced tab ที่ให้คุณใส่ Nginx directive เพิ่มเติมได้โดยตรง เหมาะสำหรับการปรับแต่งที่ UI ปกติไม่รองรับ
ตัวอย่าง Custom Config ที่ใช้บ่อย
เพิ่ม Upload Size สำหรับ WordPress
# ใส่ใน Advanced tab ของ Proxy Host client_max_body_size 100m;
ตั้ง Timeout สำหรับ Long-running Request
proxy_read_timeout 300; proxy_connect_timeout 300; proxy_send_timeout 300;
ส่ง Header ต้นฉบับสำหรับ WordPress (Real IP)
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host;
เพิ่ม Security Headers
add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
ปิด Buffering สำหรับ Streaming / Server-Sent Events
proxy_buffering off; proxy_cache off;
ข้อควรระวัง: Custom config ใน Advanced tab ต้องเป็น Nginx directive ที่ถูกต้องเท่านั้น ถ้าใส่ directive ที่ผิด Syntax NPM จะแสดงข้อผิดพลาดและไม่ Save ตรวจสอบ Syntax ก่อนนำไปใช้เสมอ
Redirect Host
Redirection Host ใช้สำหรับ Redirect Domain หนึ่งไปยังอีก URL อย่างง่าย เช่น Redirect example.com ไปยัง www.example.com หรือ Redirect Domain เก่าไปยัง Domain ใหม่
วิธีตั้งค่า Redirect Host
- ไปที่ Hosts → Redirection Hosts → Add Redirection Host
-
กรอกข้อมูล
- Domain Names: Domain ต้นทาง เช่น
example.com(ไม่มี www) - Scheme: https
- Forward Domain Name: Domain ปลายทาง เช่น
www.example.com - HTTP Code: เลือก
301สำหรับ Permanent Redirect (ดีต่อ SEO) - Preserve Path: เปิดเพื่อให้ Path เดิมติดไปด้วย เช่น
/aboutยังคงเป็น/about
- Domain Names: Domain ต้นทาง เช่น
-
ตั้งค่า SSL
เพิ่ม SSL Certificate ให้ Redirect Host ด้วย เพื่อให้ HTTP Request ถูก Redirect ไปยัง HTTPS ได้ถูกต้อง
Streams — TCP/UDP Proxy
Streams ใช้สำหรับ Forward non-HTTP traffic ที่ไม่ใช่ HTTP/HTTPS เช่น Database Port, Mail Port หรือ Game Server ซึ่ง Nginx Reverse Proxy ปกติไม่รองรับ
ตัวอย่าง: Forward MySQL Port (3306)
สถานการณ์: คุณต้องการเข้าถึง MySQL ที่รันใน Docker Container จาก Client ภายนอก VPS (เช่น DBeaver บนเครื่องของคุณ) โดยไม่เปิด Port 3306 โดยตรง
# ใน Streams — Add Stream Incoming Port: 33060 # Port ที่ Client จะ Connect มา (เลือก Port ที่ไม่ซ้ำ) Forward Host: mysql_container # Container name หรือ IP Forward Port: 3306 TCP Forwarding: ON UDP Forwarding: OFF
ข้อควรระวัง: การ Expose Database Port ออก Internet แม้ผ่าน Proxy เป็นความเสี่ยงด้าน Security ควรจำกัดด้วย Access List หรือ Firewall ให้เข้าได้เฉพาะ IP ที่เชื่อถือเท่านั้น
ดู Logs และ Debug
เมื่อ Proxy Host แสดงสถานะ Error หรือ Offline มีหลายวิธีในการ Debug
ดู Realtime Log ของ NPM Container
# ดู Log ของ NPM app container แบบ realtime cd ~/npm && docker compose logs -f app # ดู Log เฉพาะ 100 บรรทัดล่าสุด docker compose logs --tail=100 app # ดู Log ของ database container docker compose logs -f db
ปัญหาที่พบบ่อยและวิธีแก้
502 Bad Gateway
เกิดขึ้นเมื่อ NPM เชื่อมต่อไปยัง Backend Service ไม่ได้ สาเหตุที่พบบ่อย:
- Service ยังไม่พร้อมหรือ Crash — ตรวจสอบด้วย
docker psหรือsystemctl status servicename - Forward Hostname ผิด — ถ้าใช้ Container name ตรวจสอบว่าสะกดถูกต้องและ Container อยู่ใน Network เดียวกัน
- Forward Port ผิด — ตรวจสอบว่า Service ฟัง Port อะไรจริง ๆ
# ตรวจสอบ Container ที่รันอยู่ docker ps # ทดสอบ Connect ไปยัง Service จาก NPM Container docker exec npm-app-1 curl -s http://CONTAINER_NAME:PORT
SSL Certificate ไม่ออก (Failed)
- DNS ยังไม่ Propagate — ตรวจสอบว่า A Record ชี้มาที่ IP VPS ถูกต้องแล้ว
- Port 80 ถูก Block — Let's Encrypt HTTP Challenge ต้องการ Port 80 เปิดอยู่
- Rate Limit — Let's Encrypt จำกัด 5 cert ต่อ domain ต่อสัปดาห์ ถ้า Fail หลายครั้งอาจ Rate Limited
# ตรวจสอบว่า Port 80 เปิดอยู่จาก VPS curl -I http://YOUR_DOMAIN # ตรวจสอบ DNS dig +short YOUR_DOMAIN A
Too Many Redirects
เกิดขึ้นเมื่อเปิด Force SSL ใน NPM และ Service ปลายทางก็ Redirect HTTP → HTTPS เองอยู่แล้ว ทำให้วนซ้ำ
# แก้: ปิด Redirect ใน Service ปลายทาง # หรือตั้ง Scheme เป็น https ใน Proxy Host ถ้า Service ปลายทางรัน HTTPS
Connection Refused
เกิดขึ้นเมื่อ Port ที่ Forward ไปไม่มีใครฟังอยู่ หรือ Service ไม่ได้อยู่ใน Docker Network เดียวกัน
# ตรวจสอบว่า Container อยู่ใน npm_network docker network inspect npm_network | grep -A2 '"Name"' # เพิ่ม Container เข้า npm_network (runtime) docker network connect npm_network CONTAINER_NAME
Security Hardening สำหรับ NPM
NPM Web UI ที่รันบน Port 81 ไม่ควร Expose บน Public Internet เพราะถ้ามีคนเข้าถึงได้ก็สามารถเปลี่ยน Proxy config ทั้งหมดได้ ต่อไปนี้คือวิธี Harden NPM
วิธีที่ 1: Block Port 81 จาก Public Internet
# Block Port 81 จาก UFW หลัง Setup เสร็จ ufw deny 81 # ตรวจสอบ ufw status numbered
วิธีที่ 2: เข้า NPM Web UI ผ่าน SSH Tunnel
เมื่อ Block Port 81 แล้ว คุณยังเข้า NPM UI ได้ผ่าน SSH Tunnel โดยรันคำสั่งนี้บนเครื่อง Local ของคุณ
# รันบนเครื่อง Local ของคุณ (ไม่ใช่บน Server) ssh -L 81:localhost:81 user@YOUR_VPS_IP # จากนั้นเปิด Browser แล้วไปที่ http://localhost:81
คำสั่งนี้สร้าง Encrypted Tunnel ส่ง Traffic จาก Port 81 บนเครื่อง Local ของคุณไปยัง Port 81 บน Server โดยผ่าน SSH ทำให้ Secure โดยไม่ต้องเปิด Port 81 ให้ Public
วิธีที่ 3: จำกัด Port 81 ด้วย Firewall ให้เข้าได้เฉพาะ IP ของคุณ
# อนุญาตเฉพาะ IP ของคุณ (เปลี่ยน 203.0.113.10 เป็น IP จริง) ufw allow from 203.0.113.10 to any port 81 # Block จาก IP อื่นทั้งหมด ufw deny 81
วิธีที่ 4: เปลี่ยน Default Admin Email และ Password
ตรวจสอบว่าคุณได้เปลี่ยน Admin Email และ Password จาก Default ค่า [email protected] / changeme แล้ว ถ้ายังไม่ได้เปลี่ยน ให้ไปที่ Admin → Profile ใน NPM UI
Backup และ Update
การ Backup NPM ที่สำคัญที่สุดคือ Directory data, letsencrypt และ mysql ใน ~/npm/ เพราะ Directory เหล่านี้เก็บ Config, SSL Cert และ Database ทั้งหมด
Backup
# Backup ด้วย cp (ทำขณะ Container หยุดเพื่อความปลอดภัย) cd ~/npm && docker compose stop # Backup ไปยัง /backup/ (สร้าง directory ตามวันที่) mkdir -p /backup/npm-$(date +%Y%m%d) cp -r ~/npm/data ~/npm/letsencrypt ~/npm/mysql /backup/npm-$(date +%Y%m%d)/ # Start อีกครั้ง docker compose up -d # ดู Backup ที่สร้าง ls -la /backup/
Update NPM เป็นเวอร์ชันล่าสุด
# Pull Image เวอร์ชันล่าสุด cd ~/npm && docker compose pull # Recreate Container ด้วย Image ใหม่ (Downtime สั้นมาก) docker compose up -d # ตรวจสอบเวอร์ชัน docker compose exec app nginx -v
ควร Backup ก่อน Update ทุกครั้ง: แม้ NPM จะ Update ได้ง่ายมาก แต่ควร Backup data directory ก่อนทุกครั้งเพื่อป้องกัน Migration Issue ที่อาจเกิดขึ้นกับ Database Schema ในกรณีที่ Major Version เปลี่ยน
Structure ของ Data Directory
~/npm/data/— เก็บ NPM Config ทั้งหมด (Proxy Hosts, Access Lists, Settings)~/npm/letsencrypt/— เก็บ SSL Certificate และ Private Key ทั้งหมด~/npm/mysql/— เก็บ MariaDB Database ที่ NPM ใช้
สรุปและ Next Steps
Nginx Proxy Manager เป็นเครื่องมือที่ยอดเยี่ยมสำหรับ VPS ที่รันหลาย Service ทำให้การจัดการ Reverse Proxy และ SSL กลายเป็นเรื่องง่ายที่ใครก็ทำได้ผ่าน Web UI โดยไม่ต้องเขียน Nginx Config ด้วยมือ
เหมาะสำหรับ
- VPS ที่รัน 2 Service ขึ้นไปและต้องการให้แต่ละ Service มี Domain ของตัวเอง
- ผู้ที่ต้องการออก SSL Certificate ง่าย ๆ โดยไม่ต้องเรียนรู้ Certbot
- ทีมที่ต้องการ Delegate การจัดการ Proxy โดยไม่ต้อง SSH เข้า Server
- Homelab, Self-hosted Services และ Development Environment
ข้อจำกัดที่ควรรู้
- ต้องการ Docker — ไม่เหมาะกับ Server ที่ไม่ต้องการ Docker
- ต้องการ RAM อย่างน้อย 512MB (แนะนำ 1GB) เพราะรัน MariaDB ด้วย
- สำหรับ Enterprise หรือ Kubernetes อาจเหมาะกับ Traefik หรือ Ingress Controller มากกว่า
- NPM เป็น Open Source Community Project — ไม่มี Commercial Support อย่างเป็นทางการ
Next Steps ที่แนะนำ
- ลอง Deploy WordPress + NPM + SSL ทั้งหมดใน docker-compose เดียว
- ตั้ง Monitoring ด้วย Grafana + Prometheus แล้วใช้ NPM เป็น Proxy
- ตั้ง Portainer และใช้ NPM เป็น Proxy เพื่อจัดการ Docker ผ่าน Web UI อย่างปลอดภัย
- สำรวจ NPM API สำหรับ Automate การสร้าง Proxy Host
พร้อมเริ่มต้น VPS สำหรับ Nginx Proxy Manager?
VPS AsiaGB ให้ Full Root Access, RAM เริ่มต้น 1GB ขึ้นไป รองรับ Docker และ Docker Compose ได้ทันที ดาต้าเซ็นเตอร์ไทย และ สิงคโปร์ เริ่มต้น 500 บาท/เดือน
ดู VPS AsiaGB