Cách dùng Nginx Proxy Manager để public ứng dụng Docker an toàn trong 10 phút
Bạn có một app chạy Docker ở nhà, VPS, homelab: n8n, Uptime Kuma, Ghost, Portainer, Nextcloud, API nội bộ… App chạy ngon ở http://localhost:3000, nhưng muốn truy cập qua domain đẹp như https://app.example.com.
Cách “thô” thường là mở port app ra Internet. Ví dụ expose 3000:3000, trỏ domain vào IP, xong. Nhanh, nhưng rủi ro: không HTTPS, lộ port, khó quản lý nhiều app, cấu hình SSL thủ công, app nào cũng phải tự lo bảo mật tầng ngoài.
Mục tiêu bài này: trong khoảng 10 phút, bạn sẽ public một ứng dụng Docker qua domain HTTPS, có SSL, hạn chế expose port, cấu hình an toàn cơ bản.
Nginx Proxy Manager là gì?
Nginx Proxy Manager — thường gọi tắt là NPM — là lớp giao diện quản trị cho Nginx reverse proxy.Thay vì tự viết:
server {
listen 443 ssl;
server_name app.example.com;
location / {
proxy_pass http://app:3000;
}
}
Bạn thao tác bằng UI:
– Nhập domain. – Nhập IP/container/port backend. – Bật SSL. – Chọn Let’s Encrypt. – Lưu.
NPM sẽ tạo config Nginx phía sau.
Khi nào nên dùng NPM?
Rất hợp khi bạn có:
– Nhiều app Docker trên cùng VPS.
– Nhiều subdomain: n8n.example.com, status.example.com, api.example.com.
– Muốn HTTPS miễn phí, tự gia hạn.
– Muốn giấu port thật của app.
– Muốn có Basic Auth, Access List, redirect, custom headers.
– Không muốn maintain config Nginx thủ công.
Không nên dùng nếu bạn cần hạ tầng cực lớn, config phức tạp, service mesh, zero-downtime routing nâng cao. Khi đó dùng Nginx thuần, Traefik, Caddy, Kubernetes Ingress sẽ hợp hơn.
Kiến trúc đơn giản
Mô hình cơ bản:
Internet
↓
Domain: app.example.com
↓
Port 80/443 trên VPS
↓
Nginx Proxy Manager
↓
Docker app nội bộ: app:3000Điểm quan trọng: chỉ NPM cần public port 80 và 443. App phía sau không cần mở trực tiếp ra Internet.
Ví dụ sai:
ports:
- "3000:3000"Ví dụ tốt hơn:
expose:
- "3000"Hoặc không cần ports, miễn là NPM và app cùng Docker network.
Chuẩn bị trước khi bắt đầu
Bạn cần:
– Một VPS hoặc máy chủ có IP public.
– Docker + Docker Compose.
– Một domain/subdomain.
– Quyền chỉnh DNS.
– Port 80 và 443 mở trên firewall/security group.
Kiểm tra Docker:
docker --version
docker compose versionTạo bản ghi DNS:
Type: A
Name: app
Value: <IP_VPS>Ví dụ:
app.example.com → 123.123.123.123Nếu dùng Cloudflare, lúc xin SSL lần đầu nên để proxy status là DNS only. Sau khi ổn, có thể bật lại orange cloud nếu hiểu rõ SSL mode.
Cài Nginx Proxy Manager bằng Docker Compose
Tạo thư mục:
mkdir -p ~/nginx-proxy-manager
cd ~/nginx-proxy-managerTạo file docker-compose.yml:
services:
npm:
image: jc21/nginx-proxy-manager:latest
container_name: npm
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "81:81"
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
networks:
- proxy
networks:
proxy:
name: proxy
Chạy:
docker compose up -dMở UI:
http://<IP_VPS>:81Thông tin đăng nhập mặc định:
Email: [email protected]
Password: changemeViệc đầu tiên: đổi email và password ngay.
Port 81 là cổng quản trị. Sau khi cấu hình xong, không nên để public tự do. Có thể giới hạn bằng firewall, VPN, Tailscale, hoặc chỉ cho IP cá nhân truy cập.
Chạy thử một ứng dụng Docker nội bộ
Ví dụ dùng Uptime Kuma:
mkdir -p ~/uptime-kuma
cd ~/uptime-kumaTạo docker-compose.yml:
services:
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
restart: unless-stopped
expose:
- "3001"
volumes:
- ./data:/app/data
networks:
- proxy
networks:
proxy:
external: true
Chạy:
docker compose up -dLưu ý: app không expose port ra host. Nó chỉ nằm trong Docker network proxy, nơi NPM có thể truy cập.
Tạo Proxy Host trong NPM
Vào giao diện NPM:
Hosts → Proxy Hosts → Add Proxy HostTab Details:
Domain Names: status.example.com
Scheme: http
Forward Hostname / IP: uptime-kuma
Forward Port: 3001Bật:
– Block Common Exploits – Websockets Support nếu app cần realtime/websocket
Không bật cache nếu chưa chắc app phù hợp.
Bấm Save.
Lúc này thử:
http://status.example.comNếu DNS đã trỏ đúng, bạn sẽ thấy app.
Bật HTTPS miễn phí với Let’s Encrypt
Mở lại Proxy Host vừa tạo:
Edit → SSLChọn:
SSL Certificate: Request a new SSL CertificateBật:
– Force SSL – HTTP/2 Support – HSTS Enabled nếu bạn chắc domain luôn dùng HTTPS – I Agree to the Let’s Encrypt Terms of Service
Nhập email thật để nhận cảnh báo hết hạn cert.
Bấm Save.
Sau vài giây, truy cập:
https://status.example.comNếu thành công, bạn đã public app Docker bằng HTTPS.
Cấu hình an toàn tối thiểu
Public app không chỉ là “truy cập được”. Cần giảm bề mặt tấn công.
1. Không expose port app ra Internet
Tránh:
ports:
- "3001:3001"Ưu tiên:
expose:
- "3001"Hoặc chỉ dùng Docker network nội bộ.
Lý do: nếu app có lỗi auth, dashboard debug, API chưa khóa, attacker có thể truy cập thẳng qua port thật, bỏ qua proxy.
2. Khóa port quản trị NPM
Port 81 rất nhạy cảm. Ít nhất nên giới hạn firewall.
Ví dụ với UFW:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from <IP_CUA_BAN> to any port 81 proto tcp
sudo ufw enableNếu IP cá nhân thay đổi thường xuyên, dùng VPN/Tailscale/ZeroTier sẽ ổn hơn.
3. Đặt password mạnh
Đổi ngay tài khoản admin mặc định. Dùng password manager. Không dùng lại password.
4. Bật Access List cho app nội bộ
Với app nhạy cảm như Portainer, admin panel, database UI:
Access Lists → Add Access ListCó thể thêm:
– Basic Auth. – Allow/deny IP. – Chỉ cho IP công ty/VPN.
Sau đó gán Access List vào Proxy Host.
5. Bật bảo vệ cơ bản
Trong Proxy Host:
– Block Common Exploits: nên bật. – Force SSL: nên bật. – HTTP/2: nên bật. – HSTS: chỉ bật khi chắc chắn không cần HTTP nữa.
HSTS có thể gây khó chịu nếu cấu hình sai, vì trình duyệt sẽ ép HTTPS trong thời gian dài.
Lỗi thường gặp và cách xử lý nhanh
SSL không xin được
Nguyên nhân phổ biến:
– DNS chưa trỏ đúng IP. – Port 80 bị chặn. – Cloudflare đang proxy sai mode. – Domain nhập sai. – NPM không reachable từ Internet.
Kiểm tra:
dig status.example.com
curl -I http://status.example.com502 Bad Gateway
NPM không gọi được backend.
Kiểm tra:
– Container app có chạy không:
docker ps– NPM và app có cùng network không:
docker network inspect proxy– Forward hostname đúng tên service/container chưa. – Forward port đúng port nội bộ chưa.
Websocket lỗi
Bật:
Websockets SupportMột số app như n8n, Uptime Kuma, code-server, Home Assistant cần tùy chọn này.
App redirect sai domain
Một số app cần cấu hình biến môi trường public URL.
Ví dụ n8n thường cần:
environment:
- N8N_HOST=n8n.example.com
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://n8n.example.com/Nếu không, app có thể redirect về localhost hoặc URL nội bộ.
Backup và cập nhật
NPM lưu dữ liệu ở:
./data
./letsencryptBackup hai thư mục này là đủ cho phần lớn setup.
Ví dụ:
tar -czf npm-backup.tar.gz ~/nginx-proxy-manager/data ~/nginx-proxy-manager/letsencryptCập nhật:
cd ~/nginx-proxy-manager
docker compose pull
docker compose up -dNên backup trước khi update, nhất là server đang chạy nhiều app quan trọng.
Kết luận thực tế
Nginx Proxy Manager là cách nhanh, gọn, dễ vận hành để public ứng dụng Docker qua HTTPS. Với một Docker network chung, vài bản ghi DNS, một Proxy Host, bạn có thể đưa app ra Internet trong khoảng 10 phút mà không cần viết config Nginx thủ công.
Công thức an toàn tối thiểu:
– Chỉ mở port 80/443.
– Không expose port app.
– Khóa port admin 81.
– Bật SSL, Force SSL, Block Common Exploits.
– Dùng Access List cho app nhạy cảm.
– Backup data và letsencrypt.
Nhanh không đồng nghĩa với ẩu. Public ít, khóa kỹ, backup đều. NPM lo phần proxy; bạn vẫn phải lo quyền truy cập, mật khẩu, cập nhật container, và dữ liệu phía sau.
Bình luận (0)
Chưa có bình luận. Hãy là người đầu tiên!