Hướng dẫn cấu hình Nginx làm Web Server và Reverse Proxy trên Ubuntu

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

Tại sao hầu hết server Ubuntu đều cần đến Nginx

Khi tôi lần đầu triển khai ứng dụng Node.js lên VPS Ubuntu 22.04 mới tinh với 4GB RAM, tôi chạy thẳng trên cổng 3000 và mở ra internet. Mọi thứ hoạt động — cho đến khi không còn hoạt động nữa. Ngay khi cần HTTPS, muốn host thêm ứng dụng thứ hai trên cùng server, hay cần phục vụ file tĩnh hiệu quả, chạy mình Node.js trở thành một gánh nặng.

Đây là vấn đề cốt lõi. Các runtime ứng dụng như Node, Python (Gunicorn) hay PHP-FPM rất giỏi trong việc thực thi code. Nhưng không cái nào được xây dựng để xử lý các tình huống HTTP phức tạp: chấm dứt SSL, xếp hàng kết nối khi tải cao, nén gzip, caching, hay điều hướng traffic đến nhiều backend. Đó chính là khoảng trống mà Nginx lấp đầy.

Trên server production của tôi, sau khi chuyển sang thiết lập này, thời gian phản hồi trung bình giảm từ ~90ms xuống còn ~22ms khi tải cao. Tiến trình Node không còn phải tốn CPU cho các yêu cầu tài nguyên tĩnh và có thể tập trung hoàn toàn vào logic ứng dụng.

Cài đặt

Trên Ubuntu 22.04 hoặc các hệ thống nền Debian, Nginx có sẵn trong kho APT mặc định:

sudo apt update
sudo apt install nginx -y

Sau khi cài xong, khởi động và bật tự khởi động khi reboot:

sudo systemctl start nginx
sudo systemctl enable nginx

Cho phép HTTP và HTTPS qua UFW nếu bạn đang dùng:

sudo ufw allow 'Nginx Full'

Mở IP server trong trình duyệt — bạn sẽ thấy trang chào mừng của Nginx. Điều này xác nhận web server đang chạy.

Hiểu cấu trúc cấu hình

Trước khi viết bất kỳ cấu hình nào, hãy nắm rõ Nginx lưu trữ mọi thứ ở đâu:

  • /etc/nginx/nginx.conf — cấu hình chính, bao gồm tất cả trong conf.d/sites-enabled/
  • /etc/nginx/sites-available/ — nơi lưu các file cấu hình site (chưa hoạt động cho đến khi tạo symlink)
  • /etc/nginx/sites-enabled/ — các symlink trỏ đến cấu hình đang hoạt động
  • /var/www/html/ — thư mục web root mặc định
  • /var/log/nginx/ — log truy cập và log lỗi

Quy trình là: viết cấu hình trong sites-available, rồi tạo symlink vào sites-enabled để kích hoạt. Cách này cho phép bạn vô hiệu hóa một site mà không cần xóa file cấu hình.

Cấu hình Nginx làm Static Web Server

Bắt đầu với trường hợp đơn giản nhất — phục vụ file HTML tĩnh cho một domain.

Tạo thư mục web root và trang test:

sudo mkdir -p /var/www/mysite.com/html
echo '<h1>Xin chào từ Nginx</h1>' | sudo tee /var/www/mysite.com/html/index.html

Tạo file cấu hình server block:

sudo nano /etc/nginx/sites-available/mysite.com

Dán cấu hình sau:

server {
    listen 80;
    server_name mysite.com www.mysite.com;

    root /var/www/mysite.com/html;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    access_log /var/log/nginx/mysite.access.log;
    error_log  /var/log/nginx/mysite.error.log;
}

Kích hoạt và kiểm tra:

sudo ln -s /etc/nginx/sites-available/mysite.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Bước nginx -t rất quan trọng — luôn chạy lệnh này trước khi reload. Nó phát hiện lỗi cú pháp trước khi chúng làm sập server của bạn.

Cấu hình Nginx làm Reverse Proxy

Thiết lập reverse proxy mới là lý do hầu hết mọi người tìm đến Nginx. Giả sử bạn có ứng dụng Node.js đang chạy trên cổng 3000 ở localhost. Bạn muốn http://myapp.com điều hướng toàn bộ traffic đến nó.

Tạo file cấu hình mới:

sudo nano /etc/nginx/sites-available/myapp.com
server {
    listen 80;
    server_name myapp.com www.myapp.com;

    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;

        proxy_connect_timeout 60s;
        proxy_read_timeout    60s;
    }

    access_log /var/log/nginx/myapp.access.log;
    error_log  /var/log/nginx/myapp.error.log;
}

Đừng bỏ qua các dòng proxy_set_header. Nếu thiếu chúng, backend sẽ thấy mọi request đến từ 127.0.0.1 thay vì IP thực của client — điều này phá vỡ rate limiting, logging và geolocation cùng một lúc.

Kích hoạt:

sudo ln -s /etc/nginx/sites-available/myapp.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Proxy đến nhiều Backend

Nếu bạn chạy hai dịch vụ trên cùng server — chẳng hạn API trên cổng 3000 và frontend trên cổng 5000 — bạn có thể điều hướng theo đường dẫn dưới một domain duy nhất:

server {
    listen 80;
    server_name platform.com;

    location /api/ {
        proxy_pass http://127.0.0.1:3000/;
        proxy_set_header Host            $host;
        proxy_set_header X-Real-IP       $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location / {
        proxy_pass http://127.0.0.1:5000;
        proxy_set_header Host            $host;
        proxy_set_header X-Real-IP       $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Nginx khớp các location từ trên xuống dưới, ưu tiên prefix dài nhất. Các request đến /api/users sẽ đi đến cổng 3000; mọi thứ còn lại đi đến cổng 5000.

Thêm SSL với Let’s Encrypt

HTTP thuần không có chỗ đứng trong môi trường production. Trình duyệt hiển thị cảnh báo “Không bảo mật”, và Google chủ động hạ thứ hạng tìm kiếm của các site không dùng HTTPS. Giải pháp hoàn toàn miễn phí — cài Certbot và lấy chứng chỉ:

sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d myapp.com -d www.myapp.com

Certbot tự động chỉnh sửa cấu hình Nginx của bạn, thêm block listen 443 ssl và chuyển hướng HTTP sang HTTPS. Việc gia hạn được xử lý bởi systemd timer — kiểm tra bằng:

sudo certbot renew --dry-run

Kiểm tra và Giám sát

Sau mỗi lần thay đổi cấu hình, đây là các bước kiểm tra tôi luôn thực hiện.

Kiểm tra cú pháp và Reload

sudo nginx -t
sudo systemctl reload nginx

Đừng dùng restart trên production trừ khi thực sự cần thiết — reload áp dụng cấu hình mới với zero downtime bằng cách xử lý xong các kết nối hiện tại trước.

Trạng thái dịch vụ

sudo systemctl status nginx

Tìm dòng active (running). Nếu hiển thị failed, thông báo lỗi thường chỉ ra chính xác dòng cấu hình nào gây ra vấn đề.

Giám sát request theo thời gian thực

Theo dõi traffic trực tiếp đến một site cụ thể:

sudo tail -f /var/log/nginx/myapp.access.log

Hoặc chỉ lọc các lỗi:

sudo tail -f /var/log/nginx/myapp.error.log | grep -v 'favicon'

Kiểm tra Proxy Headers

Dùng curl để xác minh reverse proxy đang chuyển tiếp đúng và trả về mã trạng thái phù hợp:

curl -I http://myapp.com
curl -v http://myapp.com/api/health

Kiểm tra header X-Forwarded-For trong log ứng dụng để xác nhận IP thực của client đã được truyền qua.

Trang trạng thái Nginx (Tùy chọn)

Để xem các chỉ số kết nối cơ bản, bật module stub status:

location /nginx_status {
    stub_status;
    allow 127.0.0.1;
    deny all;
}

Rồi truy vấn ở localhost:

curl http://127.0.0.1/nginx_status

Lệnh này xuất ra số kết nối đang hoạt động, số request mỗi giây và số lượng kết nối đang đọc/ghi/chờ — hữu ích cho kiểm tra nhanh năng lực hệ thống mà không cần cài cả một stack giám sát đầy đủ.

Các lỗi thường gặp

  • 502 Bad Gateway — backend của bạn chưa chạy, hoặc đang chạy trên cổng khác với những gì bạn đã khai báo trong proxy_pass. Kiểm tra bằng ss -tlnp | grep 3000.
  • 413 Request Entity Too Large — thêm client_max_body_size 50M; vào server block nếu người dùng cần upload file.
  • Vòng lặp redirect với SSL — nếu backend phát hiện HTTPS qua X-Forwarded-Proto rồi redirect, hãy chắc chắn bạn đang set header đó. Thiếu nó sẽ gây ra vòng lặp redirect vô tận.
  • Quên tắt site mặc định — cấu hình default sẽ bắt tất cả traffic không khớp với site nào. Xóa nó bằng sudo rm /etc/nginx/sites-enabled/default.
Share: