SSL
NPM
APP
Proxy Manager
domain • ssl • docker

Nginx Proxy Manager với Docker Compose và SSL

Chạy Nginx Proxy Manager bằng Docker Compose, trỏ nhiều domain về một server, reverse proxy app nội bộ và xin SSL Let's Encrypt.

9 phút đọc15/06/2026

Khi nào nên dùng Nginx Proxy Manager

Nếu bạn có vài app self-host chạy trong nhà hoặc trên VPS như:

  • app:3000
  • gitea:3001
  • n8n:5678
  • home-assistant:8123

và muốn dùng chung một IP để trỏ nhiều domain hoặc subdomain khác nhau vào từng app, thì Nginx Proxy Manager là một trong những cách nhanh nhất để dựng reverse proxy mà không phải tự viết config Nginx bằng tay.

thì sớm muộn gì bạn cũng cần một reverse proxy phía trước để:

  • trỏ nhiều domain hoặc subdomain vào các app khác nhau
  • xin SSL cho từng hostname
  • tránh phải tự viết config Nginx bằng tay

Nginx Proxy Manager, thường gọi tắt là Nginx Proxy Manager (NPM), giải quyết đúng bài toán này. Nó là một giao diện web đặt lên trên Nginx, giúp bạn tạo proxy host, redirect và SSL chỉ bằng vài form cơ bản.

Sơ đồ Nginx Proxy Manager: domain đi vào NPM, NPM reverse proxy về từng app Docker khác nhau và tự xin SSL

Vì sao dùng Nginx Proxy Manager thay vì tự viết Nginx config

NPM không phải lựa chọn duy nhất, nhưng nó rất hợp khi bạn muốn:

  • setup nhanh
  • ít đụng file config
  • quản lý nhiều subdomain bằng giao diện
  • xin SSL Let's Encrypt mà không phải tự viết certbot flow

Nếu bạn chỉ có 1-2 app và rất quen Nginx thuần, tự viết config vẫn được. Nhưng nếu bạn muốn deploy nhanh cho homelab hoặc VPS nhỏ, NPM thường tiết kiệm thời gian hơn hẳn.

Checklist trước khi bấm Request SSL

Để Nginx Proxy Manager xin được SSL cho domain, bạn cần đủ 3 điều kiện:

  1. Domain hoặc subdomain đã trỏ về IP của server
  2. Port 80443 đi vào được máy đang chạy NPM
  3. App đích đang chạy ổn ở local network hoặc Docker network

Ví dụ:

  • app.example.com -> IP server
  • git.example.com -> IP server

Nếu DNS chưa trỏ đúng hoặc port 80/443 chưa mở, bước xin SSL sẽ fail.

Chạy Nginx Proxy Manager bằng Docker Compose

Một file tối thiểu:

services:
  npm:
    image: jc21/nginx-proxy-manager:latest
    restart: unless-stopped
    ports:
      - "80:80"
      - "81:81"
      - "443:443"
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt

Chạy lên:

docker compose up -d

Ý nghĩa các port:

  • 80: HTTP public để nhận request và dùng cho ACME challenge
  • 443: HTTPS public sau khi có SSL
  • 81: trang quản trị của NPM

Sau khi container chạy, mở:

http://<server-ip>:81

Tài khoản mặc định thường là:

Email:    [email protected]
Password: changeme

Vào lần đầu, NPM sẽ bắt bạn đổi email và password.

Trỏ domain về server trước

Ví dụ bạn muốn public app ở app.example.com, thì trên DNS provider bạn cần tạo record:

Type: A
Name: app
Value: <PUBLIC_IP_CUA_SERVER>

Nếu dùng nhiều app, cứ tạo thêm:

  • git.example.com
  • n8n.example.com
  • dash.example.com

Tất cả cùng có thể trỏ về một IP, vì phần phân luồng sẽ do Nginx Proxy Manager xử lý.

Tạo Proxy Host trong NPM

Trong giao diện NPM:

Hosts → Proxy Hosts → Add Proxy Host

Điền ví dụ:

  • Domain Names: app.example.com
  • Scheme: http
  • Forward Hostname / IP: app
  • Forward Port: 3000

Nếu app của bạn chạy cùng Docker network với NPM, hãy dùng tên service Docker như app. Nếu app chạy ngoài Docker, có thể dùng IP nội bộ như 192.168.1.10.

Thường nên bật:

  • Block Common Exploits
  • Websockets Support nếu app dùng websocket

Xin SSL ngay trên giao diện

Sau khi điền xong tab proxy, sang tab SSL:

  • chọn Request a new SSL Certificate
  • bật Force SSL
  • bật HTTP/2 Support
  • bật Agree to the Let's Encrypt Terms of Service
  • nhập email nhận thông báo certificate

Nhấn Save.

Nếu DNS và port 80/443 đều đúng, NPM sẽ tự xin certificate và bật HTTPS cho hostname đó.

Một ví dụ rất thực tế với Docker Compose nhiều service

Giả sử bạn có 2 file:

docker-compose.yml cho app:

services:
  app:
    image: myapp:latest
    restart: unless-stopped
    expose:
      - "3000"

docker-compose.npm.yml cho Nginx Proxy Manager:

services:
  npm:
    image: jc21/nginx-proxy-manager:latest
    restart: unless-stopped
    ports:
      - "80:80"
      - "81:81"
      - "443:443"
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt

Nếu muốn NPM gọi được service app bằng tên Docker, hai container cần ở cùng network. Ví dụ đơn giản:

networks:
  proxy:
    external: true

Rồi gắn cả appnpm vào network proxy.

Khi đó trong NPM bạn chỉ cần điền:

  • Domain: app.example.com
  • Forward Hostname: app
  • Port: 3000

Những lỗi hay gặp nhất

1. Domain chưa trỏ đúng IP

Đây là lỗi phổ biến nhất khi xin SSL fail. Hãy kiểm tra lại DNS A record hoặc CNAME record trước.

2. Port 80 hoặc 443 bị chiếm

Nếu máy đã có Nginx, Apache hoặc container khác bind 80/443, NPM sẽ không start được hoặc SSL challenge sẽ lỗi.

Kiểm tra:

ss -tulpn | grep -E ':80|:443|:81'

3. Forward Hostname sai

Nếu NPM và app chạy trong Docker nhưng khác network, điền app sẽ không resolve được. Khi đó:

  • hoặc cho chúng vào cùng Docker network
  • hoặc dùng IP nội bộ thật của app server

4. App tự redirect HTTPS sai cách

Một số app tự force HTTPS ở phía sau proxy nhưng không đọc đúng header X-Forwarded-Proto, dẫn tới loop redirect. Khi gặp lỗi này, hãy kiểm tra config trust proxy của app.

Khi nào NPM không phải lựa chọn tốt nhất

NPM rất tiện, nhưng không phải lúc nào cũng tối ưu nhất.

Không nên dùng nếu:

  • bạn muốn config Nginx rất phức tạp, custom sâu
  • bạn cần infrastructure-as-code chặt chẽ hơn UI
  • bạn thích dynamic reverse proxy kiểu Traefik auto-discover theo label

Nhưng nếu mục tiêu là "cho app chạy nhanh, có domain, có SSL", Nginx Proxy Manager vẫn là một công cụ rất hợp lý.

Kết luận

Nginx Proxy Manager là cách khá gọn để dựng reverse proxy cho homelab hoặc VPS nhỏ:

  • chạy nhanh bằng Docker Compose
  • trỏ nhiều domain vào nhiều app khác nhau
  • xin SSL Let's Encrypt ngay trên giao diện

Nếu bạn đang có vài container nội bộ và chưa muốn tự viết Nginx config bằng tay, đây thường là điểm bắt đầu tốt nhất.