Giải mã lỗiCó thể bạn đang thấy lỗi 502 Bad Gateway hoặc 504 Gateway Timeout trên trình duyệt. Mặc dù các lỗi này khá chung chung, nhưng nguyên nhân thực sự nằm trong log lỗi của Nginx (thường tại /var/log/nginx/error.log). Tại đó, bạn sẽ tìm thấy một dòng thông báo cụ thể như sau:
2023/10/27 14:30:15 [error] 12345#0: *67890 no live upstreams while connecting to upstream, client: 192.168.1.1, server: example.com, request: "GET /api/v1/data HTTP/1.1", upstream: "http://backend_cluster", host: "example.com"
Điều gì thực sự đang xảy ra?Hãy coi lỗi này như việc Nginx đang "bảo vệ quá mức". Nó sử dụng hệ thống kiểm tra sức khỏe thụ động (passive health check) để giám sát các máy chủ backend. Nếu một backend thất bại một số lần nhất định (max_fails) trong một khoảng thời gian cụ thể (fail_timeout), Nginx sẽ coi máy chủ đó là không đáng tin cậy và tạm thời loại bỏ nó khỏi danh sách điều phối. Khi Nginx đánh dấu tất cả các máy chủ trong khối upstream là "down" cùng một lúc, nó sẽ dừng lại và trả về lỗi "no live upstreams".
Các bước khắc phục sự cố### 1. Kiểm tra xem Backend có đang lắng nghe khôngBắt đầu với những điều cơ bản. Đảm bảo ứng dụng của bạn (cho dù là Node.js trên cổng 3000 hay PHP-FPM trên một socket) thực sự đang chạy. Nếu ứng dụng bị crash, Nginx sẽ không có gì để kết nối. Sử dụng ss hoặc netstat để kiểm tra cổng:
# Kiểm tra xem ứng dụng có đang lắng nghe trên cổng 8080 không
sudo ss -tulpn | grep :8080
Nếu dịch vụ đang chạy, hãy thử truy cập trực tiếp từ máy chủ Nginx. Điều này giúp bạn xác định vấn đề nằm ở cấu hình Nginx hay là vấn đề mạng sâu hơn:
curl -I http://127.0.0.1:8080
2. Nới lỏng các ràng buộc UpstreamCấu hình mặc định của Nginx khắt khe một cách đáng ngạc nhiên. Nó mặc định là max_fails=1 và fail_timeout=10s. Điều này có nghĩa là chỉ cần một lần timeout 504 hoặc một chút trễ nhịp cũng có thể khiến Nginx "cấm cửa" máy chủ đó trong 10 giây. Nếu bạn chỉ có một máy chủ backend, toàn bộ trang web của bạn coi như ngoại tuyến ngay lập tức sau một sự cố nhỏ.
Cập nhật khối upstream của bạn để "dễ dãi" hơn. Đối với nhiều môi trường production, cho phép thử lại vài lần trước khi từ bỏ sẽ an toàn hơn:
upstream backend_cluster {
# Tùy chọn A: Không bao giờ đánh dấu máy chủ là down (tốt nhất cho thiết lập đơn máy chủ)
server 127.0.0.1:8080 max_fails=0;
# Tùy chọn B: Cho phép 3 lần thất bại mỗi 30 giây
# server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
keepalive 32;
}
Thiết lập max_fails=0 là một cách "sửa nhanh" phổ biến. Nó buộc Nginx phải tiếp tục thử kết nối với backend bất kể các lỗi trước đó, điều này thường tốt hơn là hiển thị trang 502 cho mọi khách truy cập.
3. Kiểm tra SELinux và Tường lửaTrên các bản phân phối như RHEL, CentOS hoặc Fedora, SELinux có thể đang chặn kết nối. Ngay cả khi ứng dụng của bạn chạy hoàn hảo, Nginx có thể không có quyền mở một socket mạng. Kiểm tra log audit để tìm các lệnh từ chối:
sudo ausearch -m avc -ts recent
Nếu bạn thấy các lệnh từ chối liên quan đến Nginx, hãy chạy lệnh sau để cho phép Nginx kết nối với mạng:
sudo setsebool -P httpd_can_network_connect 1
4. Giải quyết vấn đề hết hạn DNSKhối upstream của bạn có sử dụng hostname như backend.internal? Nginx chỉ phân giải tên này thành địa chỉ IP một lần duy nhất khi khởi động. Nếu bạn đang sử dụng Docker, AWS ALBs hoặc môi trường cloud động nơi IP thay đổi thường xuyên, Nginx có thể đang cố gắng kết nối với một IP cũ không còn tồn tại.
Nếu bạn nghi ngờ điều này, hãy khởi động lại Nginx để buộc làm mới DNS. Để khắc phục lâu dài, hãy sử dụng biến trong proxy_pass hoặc định nghĩa một resolver trong cấu hình của bạn.
Áp dụng và kiểm tra bản sửa lỗiSau khi điều chỉnh cấu hình, hãy luôn kiểm tra cú pháp để tránh làm sập trang web do lỗi đánh máy:
sudo nginx -t
Nếu kiểm tra thành công, hãy tải lại cấu hình để áp dụng các thay đổi mà không làm ngắt các kết nối hiện tại:
sudo systemctl reload nginx
Theo dõi log trong thời gian thực để đảm bảo lỗi không quay trở lại:
tail -f /var/log/nginx/error.log | grep "no live upstreams"
Mẹo nâng cao hiệu suất
- **Bật Keepalives:** Thêm `keepalive 32;` vào khối upstream để giữ cho các kết nối luôn mở. Điều này có thể giảm tải CPU và độ trễ khoảng 10-15% khi lưu lượng truy cập cao.
- **Điều chỉnh Timeouts:** Nginx mặc định khá "thiếu kiên nhẫn". Nếu backend của bạn thỉnh thoảng xử lý các yêu cầu nặng mất hơn 60 giây, hãy tăng proxy timeout của bạn:
location / {
proxy_connect_timeout 10s; # Thời gian để thiết lập kết nối
proxy_send_timeout 60s;
proxy_read_timeout 60s; # Thời gian chờ backend phản hồi
proxy_pass http://backend_cluster;
}
Bằng cách cho backend thêm vài giây để phản hồi, bạn sẽ ngăn Nginx đánh dấu nó là "chết" quá sớm.

