Sửa lỗi 502 Bad Gateway: Khi Proxy Không Nhận Được Phản Hồi Hợp Lệ

intermediate🌐 Networking2026-05-10| Linux (Ubuntu/Debian/CentOS), Nginx, Apache, Node.js, Docker, cấu hình reverse proxy

Error Message

502 Bad Gateway
#networking#http#nginx#gateway#proxy

Lỗi

502 Bad Gateway

Lỗi này xảy ra ở tầng proxy. Nginx, Apache, load balancer hoặc Cloudflare nhận được yêu cầu của bạn bình thường — nhưng khi cố gắng chuyển tiếp yêu cầu đó lên upstream, nó không nhận được phản hồi hữu ích nào. Proxy vẫn hoạt động. Backend mới là bên không phối hợp.

Nguyên nhân thường gặp: app server bị crash, sai port, upstream timeout, hoặc cấu hình sai chỉ thị proxy_pass.

Bước 1 — Kiểm tra xem Backend có thực sự đang chạy không

Trước khi đụng vào cấu hình Nginx, hãy xác nhận tiến trình upstream còn sống.

# Kiểm tra xem app Node.js/Python/Gunicorn có đang lắng nghe không
sudo ss -tlnp | grep 3000
# hoặc
sudo netstat -tlnp | grep 3000

# Nếu không có gì hiện ra, app đã down — khởi động lại
sudo systemctl restart myapp

# Kiểm tra log của app
journalctl -u myapp -n 50 --no-pager

Nếu port đó không mở, Nginx không có gì để kết nối. Thay đổi cấu hình bao nhiêu cũng vô ích. Hãy sửa app trước.

Bước 2 — Xác minh Nginx đang trỏ đúng chỗ

Mở file cấu hình site của bạn:

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

Kiểm tra kỹ dòng proxy_pass:

location / {
    proxy_pass http://127.0.0.1:3000;  # must match your app's actual port
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
}

Bốn lỗi thường gặp gây ra lỗi này:

  • Sai port — app chạy trên 3000 nhưng cấu hình lại ghi 8080
  • Dùng localhost thay vì 127.0.0.1 khi phân giải IPv6 hoạt động không như mong đợi
  • Không nhất quán về dấu gạch chéo cuối — proxy_pass http://127.0.0.1:3000/ so với không có dấu gạch chéo sẽ thay đổi cách path được viết lại
  • Trỏ đến Unix socket không tồn tại hoặc có quyền sai

Bước 3 — Kiểm tra cài đặt Timeout của Upstream

Các truy vấn DB nặng, cold start, hoặc gọi API ngoài chậm có thể khiến backend vượt quá timeout mặc định 60 giây của Nginx. Proxy bỏ cuộc và trả về 502 trước khi phản hồi kịp đến.

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_connect_timeout 60s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;
}

Tăng các giá trị này chỉ mua thêm thời gian, không giải quyết gốc rễ. Backend mà thường xuyên mất hơn 90 giây là có vấn đề hiệu suất cần được xử lý từ nguồn.

Bước 4 — Đọc Error Log của Nginx

Theo dõi error log trước — nó thường cho bạn biết chính xác điều gì đã hỏng:

sudo tail -f /var/log/nginx/error.log

Bạn sẽ thấy nội dung kiểu như:

[error] 12345#0: *1 connect() failed (111: Connection refused) while connecting to upstream,
client: 1.2.3.4, server: example.com, request: "GET / HTTP/1.1",
upstream: "http://127.0.0.1:3000/", host: "example.com"

Connection refused = backend không chạy trên port đó. upstream timed out = backend đang chạy nhưng quá chậm hoặc bị treo.

Bước 5 — Môi trường Docker / Container

Đang chạy app trong Docker với Nginx trên host (hoặc trong container riêng)? Thì 127.0.0.1 sẽ không hoạt động — bên trong container, địa chỉ đó trỏ đến chính container, không phải máy host.

# Tùy chọn 1: Dùng IP gateway của host (Docker Desktop trên Linux)
proxy_pass http://172.17.0.1:3000;

# Tùy chọn 2: Dùng DNS nội bộ của Docker nếu cả hai cùng network
proxy_pass http://app-container-name:3000;

# Tìm IP gateway
docker network inspect bridge | grep Gateway

Trong docker-compose.yml, cả hai service cần chia sẻ cùng một network:

services:
  nginx:
    networks:
      - webnet
  app:
    networks:
      - webnet

networks:
  webnet:

Bước 6 — Unix Socket thay vì TCP Port

Gunicorn và uWSGI thường dùng Unix socket thay vì TCP port. Có hai vấn đề có thể xảy ra: file socket không tồn tại, hoặc Nginx không đọc được nó.

# Kiểm tra xem socket có tồn tại không
ls -la /run/myapp.sock

# Cấu hình Nginx cho socket
location / {
    proxy_pass http://unix:/run/myapp.sock;
}

# Sửa quyền nếu user Nginx (www-data) không đọc được
sudo chown www-data:www-data /run/myapp.sock

Xác nhận bản sửa lỗi

Kiểm tra theo thứ tự này — mỗi bước xác nhận một tầng khác nhau:

# Kiểm tra cú pháp cấu hình Nginx trước
sudo nginx -t

# Reload không có downtime
sudo systemctl reload nginx

# Xác nhận backend có thể truy cập trực tiếp (bỏ qua Nginx)
curl -v http://127.0.0.1:3000/

# Sau đó kiểm tra qua Nginx
curl -v http://yourdomain.com/

# Theo dõi access log trực tiếp
sudo tail -f /var/log/nginx/access.log

Nhận được 200 OK khi curl trực tiếp và qua Nginx là xác nhận mọi thứ đã được kết nối đúng.

Mẹo

Lỗi 502 không liên tục — chỉ xuất hiện khi tải cao, không phải lúc nào cũng có — thường có nghĩa là upstream pool đã cạn kiệt. Thêm một instance thứ hai và Nginx sẽ phân phối tải luân phiên giữa chúng:

upstream backend {
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    keepalive 32;
}

Nhân tiện, hãy thêm trang lỗi tùy chỉnh để người dùng thấy nội dung hữu ích thay vì trang 502 trần của trình duyệt:

error_page 502 /502.html;
location = /502.html {
    root /var/www/html;
    internal;
}

Khi debug các vấn đề định tuyến giữa proxy và upstream — đặc biệt trong môi trường Docker nhiều network — công cụ tính subnet trên ToolCraft giúp nhanh chóng xác minh dải CIDR và xác nhận các host có thực sự cùng network segment hay không. Giải quyết được rất nhiều vấn đề kiểu "tại sao chúng không kết nối được với nhau".

Related Error Notes