Nginx Proxy Manager: Reverse Proxy với Web UI, Không Còn Đau Đầu

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

2 Giờ Sáng và Config Nginx Của Bạn Bị Lỗi

Bạn chắc chắn đã từng trải qua cảnh này. Một dịch vụ mới vừa được triển khai, khách hàng đang thức ở múi giờ khác, và bạn đang chằm chằm nhìn vào lỗi 502 Bad Gateway vốn không hề tồn tại một tiếng trước. Bạn mở /etc/nginx/sites-available/, bắt đầu so sánh từng virtual host block, rồi nhận ra mình đã vô tình ghi đè lên một config đang hoạt động tốt khi thêm cái mới.

Tôi đã rơi vào tình huống này nhiều hơn mức tôi muốn thừa nhận. Quản lý nhiều config reverse proxy thủ công — xử lý SSL cert, định tuyến cổng, ánh xạ subdomain — rất dễ xảy ra lỗi ngay cả khi bạn đang tỉnh táo. Đó là lý do tôi bắt đầu dùng Nginx Proxy Manager, và nó lặng lẽ trở thành một trong những công cụ không thể thiếu trong stack của tôi.

Tại Sao Config Nginx Thuần Túy Lại Trở Thành Gánh Nặng

Vấn đề thực sự không phải bản thân Nginx — mà là chi phí vận hành tích lũy theo thời gian. Vài file config vẫn còn quản lý được khi bạn chỉ chạy một dịch vụ. Nhưng khi số lượng dịch vụ phía sau reverse proxy lên đến 5, 10, hay 20, những vết nứt bắt đầu lộ ra:

  • Cert Let’s Encrypt hết hạn sau mỗi 90 ngày. Việc gia hạn bằng Certbot cần thiết lập thủ công hoặc tự động hóa qua cron — và khi thất bại, bạn không biết cho đến khi người dùng bắt đầu thấy lỗi cert trên trình duyệt.
  • Thành viên mới trong nhóm không thể chỉnh sửa config nginx một cách an toàn mà không gây rủi ro cho các dịch vụ khác.
  • Không có audit trail — bạn không biết ai đã thay đổi gì, vào lúc nào.
  • Kiểm tra một thay đổi config có nghĩa là chạy nginx -t và hy vọng bạn đã bắt được mọi lỗi trước khi reload.

Các file config không phải kẻ thù thực sự. Điều còn thiếu là một giao diện an toàn, có cấu trúc để quản lý chúng — đặc biệt trong môi trường làm việc nhóm hoặc đa dịch vụ.

So Sánh Các Giải Pháp: Cách Người Ta Thường Xử Lý Vấn Đề Này

Lựa chọn 1: Viết config Nginx thủ công

Cách tiếp cận kinh điển. Toàn quyền kiểm soát, không có lớp trừu tượng, linh hoạt tối đa. Nhược điểm: mọi thứ tôi đã mô tả ở trên. Hoạt động tốt khi một mình, trở nên khổ sở khi mở rộng quy mô.

Lựa chọn 2: Traefik

Traefik rất phổ biến trong các stack nặng về Docker. Nó tự động khám phá dịch vụ qua Docker label và xử lý SSL tự động. Nhưng bạn phải tư duy theo mô hình của Traefik — middlewares, routers, entrypoints. Config dùng YAML hoặc TOML, và debug khi có sự cố không hề dễ chịu. Traefik cũng phù hợp hơn với các setup Docker Compose hoặc Kubernetes mới từ đầu. Nếu bạn đang quản lý các dịch vụ bare-metal sẵn có, cảm giác như đang nhồi cái vuông vào lỗ tròn.

Lựa chọn 3: Caddy

Caddy gọn gàng và đi kèm HTTPS tự động ngay từ đầu. Cú pháp Caddyfile đơn giản hơn nhiều so với nginx — một reverse proxy cơ bản chỉ cần đúng ba dòng. Bắt đầu từ đầu với routing đơn giản? Caddy đáng để thử. Tuy nhiên, nó không có giao diện quản lý, và các kịch bản routing phức tạp nhanh chóng đẩy bạn vào hệ sinh thái plugin của nó.

Lựa chọn 4: Nginx Proxy Manager (NPM)

NPM chạy dưới dạng Docker container và bọc Nginx bằng một giao diện web gọn gàng. Bạn thêm proxy host thông qua trình duyệt. SSL cert được cấp qua Let’s Encrypt và tự động gia hạn. Các config nginx bên dưới được tạo tự động cho bạn. Nó bao phủ 90% các trường hợp thực tế — định tuyến subdomain, bắt buộc HTTPS, quản lý kiểm soát truy cập — mà không cần chạm vào bất kỳ file config nào.

Thiết Lập Nginx Proxy Manager

Yêu cầu trước khi bắt đầu

  • VPS hoặc server đã cài Docker và Docker Compose
  • Các cổng 80, 443 và 81 được mở trong firewall
  • Một tên miền với bản ghi DNS trỏ về server của bạn

Bước 1: Tạo file Docker Compose

Tạo một thư mục cho NPM và tạo file docker-compose.yml:

mkdir -p ~/nginx-proxy-manager && cd ~/nginx-proxy-manager
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

Cổng 81 là giao diện web quản trị. Cổng 80 và 443 xử lý lưu lượng thực tế. Phần volumes giúp lưu trữ bền vững các config proxy và SSL cert qua các lần khởi động lại container. Bỏ qua nó và một lần cập nhật container sẽ xóa sạch toàn bộ thiết lập của bạn.

Bước 2: Khởi động container

docker compose up -d
docker compose logs -f app

Theo dõi log. Lần khởi động đầu tiên mất khoảng 10–15 giây để khởi tạo cơ sở dữ liệu SQLite. Khi bạn thấy thông báo sẵn sàng, là được rồi.

Bước 3: Đăng nhập vào trang quản trị

Mở http://your-server-ip:81 trong trình duyệt. Thông tin đăng nhập mặc định:

Bạn sẽ được yêu cầu thay đổi những thứ này khi đăng nhập lần đầu. Hãy làm ngay — và chặn cổng 81 khỏi truy cập công khai sau khi đã thiết lập tài khoản admin.

Bước 4: Thêm proxy host đầu tiên

Truy cập Proxy Hosts → Add Proxy Host. Điền vào:

  • Domain Names: ví dụ, app.yourdomain.com
  • Scheme: http hoặc https tùy thuộc vào dịch vụ upstream của bạn
  • Forward Hostname/IP: IP nội bộ hoặc tên container của dịch vụ
  • Forward Port: cổng mà dịch vụ lắng nghe

Chuyển sang tab SSL. Chọn Request a new SSL Certificate, đánh dấu Force SSLHTTP/2 Support, nhập email để đăng ký Let’s Encrypt, rồi lưu. NPM xử lý việc cấp cert và tự động gia hạn — không cần cấu hình cron job certbot.

Bước 5: Xử lý các dịch vụ cùng mạng Docker

Có các dịch vụ đang chạy trong Docker trên cùng một host? Đặt cả hai container vào một mạng dùng chung để NPM có thể kết nối đến chúng bằng tên container thay vì IP:

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:
      - proxy

networks:
  proxy:
    name: proxy
    driver: bridge

Sau đó trong file Compose của dịch vụ khác, khai báo mạng là external:

networks:
  proxy:
    external: true

Dùng tên container làm forward hostname trong cấu hình proxy host của NPM. Cổng của dịch vụ vẫn ở nội bộ — không có gì bị lộ ra host.

Bước 6: Hạn chế truy cập bằng Access List

NPM hỗ trợ xác thực cơ bản và danh sách trắng IP thông qua Access List. Với các dịch vụ chỉ dùng nội bộ — dashboard Grafana, Portainer, trang quản trị — hãy tạo một access list trong mục Access Lists, thêm dải IP hoặc thông tin xác thực HTTP, rồi gắn vào proxy host. Bạn có một subdomain HTTPS gọn gàng mà không vô tình để lộ các công cụ nội bộ ra internet.

Những Điều Cần Lưu Ý

NPM không hoàn hảo. Container chạy với quyền root bên trong — đáng biết nếu yêu cầu bảo mật của bạn nghiêm ngặt. Cơ sở dữ liệu SQLite (hoặc MariaDB nếu bạn cấu hình) lưu trữ toàn bộ config proxy, vì vậy hãy sao lưu nó. Volume ./data là thứ bạn muốn snapshot trước khi nâng cấp.

Cần các chỉ thị nginx tùy chỉnh, giới hạn tốc độ, hay xử lý header cụ thể? Tab Advanced của NPM cho phép bạn chèn các đoạn config nginx thuần túy cho từng proxy host. Nó không cho bạn mọi thứ mà nginx thuần có thể làm, nhưng xử lý được hầu hết các trường hợp đặc biệt mà không phải từ bỏ giao diện hoàn toàn.

Đang chạy hơn 10 dịch vụ trên VPS mà vẫn chỉnh sửa file config thủ công? Đó là thời gian bạn không bao giờ lấy lại được. Số giờ tiết kiệm được khi không phải debug đường dẫn ssl_certificate lúc 2 giờ sáng cộng dồn nhanh hơn bạn nghĩ.

Tham Khảo Nhanh

  • Giao diện quản trị: http://server-ip:81
  • Đăng nhập mặc định: [email protected] / changeme
  • SSL cert lưu trong: ./letsencrypt
  • Config proxy lưu trong: ./data
  • Cập nhật NPM: docker compose pull && docker compose up -d

Đang chạy Nginx thủ công với hơn ba bốn dịch vụ? Hãy thử NPM trong một cuối tuần trên server staging. Thiết lập nó song song với stack hiện tại. Nhiều khả năng nó xử lý được 95% những gì bạn cần với phần nhỏ chi phí bảo trì.

Share: