DeployEasy
Menu
NginxCơ bản

Nginx Reverse Proxy là gì? Cấu hình cho Node.js production

Giải thích Nginx reverse proxy, server block, proxy_pass, header, timeout và cách cấu hình nhiều domain cho ứng dụng Node.js trên VPS.

· 6 phút đọc · 1.121 từ
Mục lục bài viết

Ứng dụng Node.js thường chạy ở port nội bộ như 3000. Trong production, người dùng không nên phải truy cập https://example.com:3000. Nginx nhận request ở port 80/443 rồi chuyển tới ứng dụng nội bộ.

Nginx là gì?

Nginx là web server, reverse proxy, content cache, load balancer và TCP/UDP proxy.

Internet

Nginx :80/:443

Node.js :3000

Reverse proxy là gì?

Reverse proxy đứng trước server ứng dụng và thay mặt client gửi request tới upstream.

Client → Reverse proxy → Application

Client chỉ biết:

https://api.deployeasy.vn

Ứng dụng thật có thể chạy:

http://127.0.0.1:3001

Vì sao không public trực tiếp port app?

Production thường cần:

  • Domain.
  • HTTPS.
  • Redirect.
  • Nhiều app trên một IP.
  • Request log.
  • Upload limit.
  • Timeout.
  • Static file.
  • Load balancing.

Nginx cung cấp lớp cấu hình tập trung cho các nhu cầu này.

Cài Nginx

sudo apt update
sudo apt install -y nginx

Kiểm tra:

sudo systemctl status nginx

Firewall:

sudo ufw allow "Nginx Full"

Cấu trúc Nginx trên Ubuntu

/etc/nginx/
├── nginx.conf
├── sites-available/
├── sites-enabled/
├── conf.d/
└── snippets/
  • sites-available: lưu cấu hình.
  • sites-enabled: symlink site đang bật.

Tạo server block

sudo nano /etc/nginx/sites-available/deployeasy
server {
    listen 80;
    listen [::]:80;

    server_name deployeasy.vn www.deployeasy.vn;

    location / {
        proxy_pass http://127.0.0.1:3000;

        proxy_http_version 1.1;
        proxy_set_header Host $host;
        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;
    }
}

Bật:

sudo ln -s /etc/nginx/sites-available/deployeasy \
  /etc/nginx/sites-enabled/deployeasy

Kiểm tra và reload:

sudo nginx -t
sudo systemctl reload nginx

Giải thích cấu hình

listen

listen 80;
listen [::]:80;

Lắng nghe HTTP IPv4 và IPv6.

server_name

server_name deployeasy.vn www.deployeasy.vn;

Chọn request theo Host header.

proxy_pass

proxy_pass http://127.0.0.1:3000;

Chuyển request tới ứng dụng.

Header Host

proxy_set_header Host $host;

Giữ domain gốc cho app.

IP client

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Truyền thông tin IP qua proxy. Ứng dụng chỉ nên trust proxy đáng tin cậy.

Protocol gốc

proxy_set_header X-Forwarded-Proto $scheme;

Cho app biết request public dùng HTTP hay HTTPS.

App nên bind vào đâu?

Nếu Nginx và app cùng VPS:

127.0.0.1:3000

Ví dụ:

app.listen(3000, "127.0.0.1");

Nếu app nằm trong Docker:

ports:
  - "127.0.0.1:3000:3000"

Dấu / trong proxy_pass

Hai cấu hình sau có thể xử lý URI khác nhau:

location /api/ {
    proxy_pass http://127.0.0.1:3000/;
}
location /api/ {
    proxy_pass http://127.0.0.1:3000;
}

Khi proxy theo prefix, cần test URL thật thay vì thêm/bỏ slash theo cảm tính.

WebSocket

location /socket/ {
    proxy_pass http://127.0.0.1:3000;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    proxy_set_header Host $host;
    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;
}

Chỉ thêm khi ứng dụng cần WebSocket.

Upload file

server {
    client_max_body_size 20M;
}

Ứng dụng vẫn phải kiểm tra loại file, kích thước, tên và quyền truy cập.

Timeout

location / {
    proxy_pass http://127.0.0.1:3000;

    proxy_connect_timeout 10s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;
}

Không tăng timeout quá lớn để che API chậm. Tác vụ dài nên cân nhắc queue.

Phục vụ static file

location /uploads/ {
    alias /var/www/deployeasy/uploads/;
}

Cần chú ý permission và không phục vụ file riêng tư thiếu xác thực.

Cache asset

location ~* \.(css|js|png|jpg|jpeg|gif|svg|webp|ico)$ {
    expires 7d;
    add_header Cache-Control "public";
}

File có hash có thể cache dài hơn. Không cache HTML/API một cách máy móc.

Nhiều app trên một VPS

server {
    listen 80;
    server_name deployeasy.vn;

    location / {
        proxy_pass http://127.0.0.1:3000;
    }
}

server {
    listen 80;
    server_name api.deployeasy.vn;

    location / {
        proxy_pass http://127.0.0.1:3001;
    }
}

server {
    listen 80;
    server_name admin.deployeasy.vn;

    location / {
        proxy_pass http://127.0.0.1:3002;
    }
}

Load balancing

upstream deployeasy_api {
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
}

server {
    listen 80;
    server_name api.deployeasy.vn;

    location / {
        proxy_pass http://deployeasy_api;
    }
}

Ứng dụng cần stateless hoặc có shared session phù hợp.

Redirect www

server {
    listen 80;
    server_name www.deployeasy.vn;

    return 301 http://deployeasy.vn$request_uri;
}

Sau HTTPS, redirect về URL HTTPS chính.

Log

/var/log/nginx/access.log
/var/log/nginx/error.log

Theo dõi:

sudo tail -f /var/log/nginx/error.log
sudo journalctl -u nginx --since "30 minutes ago"

Quy trình sửa an toàn

sudo nginx -t

Chỉ reload khi hợp lệ:

sudo systemctl reload nginx

Backup:

sudo cp /etc/nginx/sites-available/deployeasy \
  /etc/nginx/sites-available/deployeasy.bak

Lỗi 502 Bad Gateway

Kiểm tra app:

curl -I http://127.0.0.1:3000
sudo ss -ltnp | grep 3000

Xem log:

sudo tail -n 100 /var/log/nginx/error.log

Nguyên nhân:

  • App chưa chạy.
  • Sai port.
  • App crash.
  • Bind sai interface.
  • Container chưa publish.
  • Timeout.
  • Socket permission.

Lỗi 404 từ Nginx

Có thể:

  • server_name không khớp.
  • Request rơi vào default server.
  • Site chưa enable.
  • Symlink sai.
  • DNS trỏ nhầm.

Xem config hiệu lực:

sudo nginx -T

CSS trả về text/html

Nếu request CSS nhận HTML, thường do:

  • File build không tồn tại.
  • Request fallback về trang HTML.
  • Deploy thiếu static asset.
  • HTML và asset khác version.
  • Nginx location sai.

Không chỉ ép Content-Type: text/css; phải sửa routing hoặc artifact.

Cấu hình mẫu

server {
    listen 80;
    listen [::]:80;

    server_name api.deployeasy.vn;

    client_max_body_size 10M;

    access_log /var/log/nginx/deployeasy-api.access.log;
    error_log /var/log/nginx/deployeasy-api.error.log;

    location / {
        proxy_pass http://127.0.0.1:3001;

        proxy_http_version 1.1;

        proxy_set_header Host $host;
        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_connect_timeout 10s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}

Checklist

[ ] DNS đúng IP
[ ] App chạy port nội bộ
[ ] curl localhost thành công
[ ] server_name đúng
[ ] proxy_pass đúng
[ ] Header proxy đủ
[ ] WebSocket nếu cần
[ ] Upload limit phù hợp
[ ] nginx -t thành công
[ ] Firewall mở 80/443
[ ] Log riêng cho app
[ ] HTTPS sau khi HTTP chạy

Câu hỏi thường gặp

Nginx có chạy app Node.js không?

Không. Node.js vẫn cần PM2, systemd, Docker hoặc runtime khác.

Có cần Nginx khi dùng Vercel?

Không cần tự cài Nginx cho deployment do Vercel quản lý.

Có nên public port 3000?

Nếu chỉ Nginx cần truy cập, nên bind localhost.

Kết luận

Nginx reverse proxy tách lớp Internet khỏi ứng dụng. Hãy làm app chạy tốt trên localhost trước, rồi mới thêm Nginx, domain và HTTPS.

Nguồn tham khảo

Đọc tiếp