Sửa lỗi Nginx: upstream timed out (110: Connection timed out) while reading response header

intermediate Nginx2026-05-02| Nginx đóng vai trò là reverse proxy hoặc FastCGI gateway trên các máy chủ Linux (Ubuntu, Debian, RHEL) với các backend như PHP-FPM, Gunicorn, hoặc Node.js.

Error Message

upstream timed out (110: Connection timed out) while reading response header from upstream
#nginx#upstream#timeout#proxy#php-fpm#gunicorn

Bối cảnh: Khi 60 giây là không đủLỗi 504 Gateway Timeout trên trình duyệt chỉ là triệu chứng. Nguyên nhân thực sự nằm trong log lỗi của Nginx. Gần đây tôi đã gặp vấn đề này khi xây dựng tính năng báo cáo xuất file PDF dung lượng 50MB. Các báo cáo nhỏ hoạt động tức thì, nhưng ngay khi tập dữ liệu lên tới hơn 5.000 dòng, yêu cầu sẽ treo đúng 60 giây rồi dừng lại.

Kiểm tra nhanh tệp /var/log/nginx/error.log đã chỉ ra vấn đề:

[error] 1234#0: *567 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 1.2.3.4, server: example.com, request: "POST /api/export HTTP/1.1", upstream: "http://127.0.0.1:8000/api/export"

Điều này có nghĩa là Nginx đã kết nối với backend của bạn—cho dù đó là PHP-FPM, Gunicorn hay Node—và gửi yêu cầu. Tuy nhiên, backend đã không gửi lại bất kỳ byte tiêu đề phản hồi (response headers) nào trước khi bộ đếm thời gian hết hạn.

Phân tích: Bức tường 60 giâyNginx rất kiên nhẫn, nhưng cũng có giới hạn. Theo mặc định, nó chờ phản hồi từ upstream trong 60 giây. Nếu ứng dụng của bạn đang bận xử lý một truy vấn cơ sở dữ liệu khổng lồ hoặc lấy dữ liệu từ một API bên thứ ba chậm chạp, nó sẽ vấp phải bức tường này. Lỗi "110: Connection timed out" là một tín hiệu mạng cụ thể. Nó cho bạn biết rằng kết nối nội bộ giữa Nginx và ứng dụng của bạn vẫn mở nhưng không có phản hồi trong quá lâu.

Cách khắc phục ngay lập tức: Gia hạn TimeoutBạn cần cung cấp cho Nginx thêm không gian để xử lý. Chỉ thị (directive) cụ thể bạn cần tùy thuộc vào cách Nginx giao tiếp với ứng dụng của bạn. Tôi thường đặt các giá trị này thành 300 giây (5 phút) cho các endpoint nặng nề.

Đối với Reverse Proxy (Node.js, Gunicorn, Go)Nếu bạn sử dụng proxy_pass, hãy cập nhật block location của mình. Việc tăng cả ba giá trị timeout đảm bảo kết nối không bị ngắt trong bất kỳ giai đoạn nào của yêu cầu.

location /api/ {
    proxy_pass http://localhost:8000;
    proxy_read_timeout 300s;
    proxy_connect_timeout 300s;
    proxy_send_timeout 300s;
}

Đối với PHP-FPM (FastCGI)Các thiết lập PHP sử dụng giao thức FastCGI. Bạn sẽ cần chỉ thị fastcgi_read_timeout ở đây. Điều này thường thấy ở các script Laravel hoặc WordPress chạy lâu.

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
    fastcgi_read_timeout 300s;
}

Đối với Python/UWSGI```

location / { include uwsgi_params; uwsgi_pass unix:/tmp/app.sock; uwsgi_read_timeout 300s; }


Tải lại Nginx để áp dụng các thay đổi:

sudo nginx -t && sudo systemctl reload nginx


## Mối liên kết còn thiếu: Cấu hình BackendThay đổi cấu hình Nginx chỉ là một mặt của vấn đề. Nếu backend của bạn có timeout riêng là 30 giây, nó sẽ ngắt tiến trình trước khi Nginx kết thúc việc chờ đợi. Bạn phải đồng bộ hóa các giới hạn này.
### Cập nhật PHP-FPMChỉnh sửa tệp `php.ini` để cho phép các script chạy lâu hơn:

max_execution_time = 300


Đồng thời, kiểm tra dòng này trong tệp `/etc/php/8.2/fpm/pool.d/www.conf`:

request_terminate_timeout = 300


### Cập nhật Gunicorn (Python)Gunicorn mặc định có thời gian timeout rất ngắn là 30 giây. Nếu bạn không thay đổi điều này, Nginx sẽ báo lỗi 'Bad Gateway' hoặc timeout khi Gunicorn ngắt worker. Hãy khởi động nó như sau:

gunicorn --timeout 300 myapp.wsgi:application


## Xác minh: Kiểm tra giới hạn mớiĐừng chỉ tin vào cấu hình. Hãy sử dụng `curl` để xem chính xác máy chủ giữ kết nối trong bao lâu:

time curl -I http://example.com/api/heavy-task


Quan sát đầu ra của thời gian 'real'. Nếu nó vượt quá 60 giây và trả về `200 OK`, bạn đã khắc phục được lỗi. Nếu nó vẫn thất bại ở mốc 300 giây, tác vụ của bạn đơn giản là quá chậm đối với một yêu cầu web tiêu chuẩn.
## Các phương pháp tốt nhấtTăng timeout chỉ là một giải pháp tình thế. Người dùng ghét phải nhìn chằm chằm vào biểu tượng đang tải trong năm phút. Đối với các tác vụ nặng, hãy chuyển logic sang một background worker như Celery hoặc Redis Queue. Hãy để người dùng kích hoạt công việc, nhận thông báo 'Job Started' và kiểm tra kết quả sau. Cách này phức tạp hơn để xây dựng nhưng đáng tin cậy hơn nhiều.

Related Error Notes