Как исправить 504 Gateway Timeout в Nginx
Определяем, где закончился таймаут, проверяем приложение напрямую и ищем задержку по журналам Nginx.

504 Gateway Timeout означает, что шлюз не дождался ответа следующего звена. В схеме «клиент → CDN → Nginx → приложение → база» ошибку может вернуть несколько компонентов. Начните с проблемного маршрута и времени запроса, затем сравните ответ прокси с ответом приложения. Так станет ясно, какой таймаут сработал и где запрос провёл время.
Найти прокси, который вернул 504
Сохраните время, метод, адрес маршрута и идентификатор запроса, если приложение его выдаёт. Для безопасной проверки используйте читающий GET без токенов в URL и без повторной отправки платежа или формы.
curl -sS --max-time 75 -o /dev/null \
-w 'status=%{http_code} connect=%{time_connect}s ttfb=%{time_starttransfer}s total=%{time_total}s\n' \
https://example.com/catalog/
sudo tail -n 80 /var/log/nginx/error.log
sudo journalctl -u myapp.service --since '15 min ago' --no-pager
ttfb показывает время до первых байтов ответа. При status=000 HTTP-ответ не получен. Например, мог закончиться лимит самого curl. Проверьте stderr и код выхода клиента.
Если перед Nginx стоит CDN, сравните ответ через CDN и прямой запрос на известный IP своего origin. --resolve оставляет домен в SNI и заголовке Host, поэтому проверка сертификата сохраняется. Пример использует адрес из диапазона для документации.
curl -sS --max-time 75 --resolve example.com:443:203.0.113.10 \
-o /dev/null -w 'origin=%{http_code} ttfb=%{time_starttransfer}s\n' \
https://example.com/catalog/
Если прямой вход ограничен адресами CDN, выполните проверку из разрешённой сети или используйте журналы origin. Открывать origin всему интернету для диагностики не требуется. Подробнее о цепочке доставки — в обзоре CDN.
Прочитать причину в журнале Nginx
| Запись | Что проверить |
|---|---|
while connecting to upstream |
Адрес и порт, слушающий сокет, firewall, сеть до приложения и очередь соединений |
while reading response header from upstream |
Ожидание заголовков. Проверьте воркеры приложения, запросы в БД и внешние вызовы |
while reading upstream |
Пауза при передаче ответа. Проверьте поток данных, генерацию файла или внешний сервис |
connect() failed (111: Connection refused) |
На целевом порту нет слушателя или соединение отвергнуто. Частый результат — 502 |
Для HTTP-upstream проверьте тот же путь напрямую на сервере. Подставьте реальный адрес, Host и маршрут с учётом переписывания URI в proxy_pass. У FastCGI-сокета другой протокол, поэтому такой curl подходит HTTP-сервисам вроде Gunicorn, Node.js или Uvicorn.
sudo ss -ltnp '( sport = :8001 )'
curl -sS --max-time 75 -H 'Host: example.com' \
-o /dev/null -w 'app=%{http_code} ttfb=%{time_starttransfer}s\n' \
http://127.0.0.1:8001/catalog/
Быстрый ответ /health/ подтверждает доступность процесса. Для поиска задержки повторите именно проблемный читающий запрос. Если зависает только конкретная страница, ищите её SQL-запросы, внешний API или тяжёлую обработку. Если одновременно медленны даже лёгкие страницы, проверьте заполнение очереди, воркеры и ресурсы VPS. Для отказа соединения есть отдельный разбор 502.
Добавить измерение времени upstream
Если задержки периодические, добавьте log_format в контекст http, а access_log — в нужный server. Такой формат записывает URI без query string. Заголовки авторизации и cookies в него не входят.
log_format upstream_timing '$remote_addr "$request_method $uri" '
'$status rt=$request_time us=$upstream_status '
'uct=$upstream_connect_time uht=$upstream_header_time '
'urt=$upstream_response_time';
access_log /var/log/nginx/myapp-timing.log upstream_timing;
uct — подключение к приложению, uht — получение заголовка, urt — время ответа upstream. rt охватывает обработку запроса целиком со стороны Nginx. При нескольких попытках upstream в поле может быть несколько значений. Для нового файла настройте ротацию и срок хранения.
Согласовать таймауты после диагностики
proxy_read_timeout ограничивает интервал между чтениями из upstream. Поток, который регулярно отдаёт данные, может продолжаться дольше этого значения. Для PHP-FPM аналогичный параметр называется fastcgi_read_timeout. Отдельно учитывайте таймаут клиента, CDN, самого приложения и внешней базы.
Если операции действительно нужно больше времени и длительность укладывается в лимит внешнего прокси, измените настройку только для её маршрута. Пример для HTTP-upstream:
location /reports/ {
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8001;
proxy_connect_timeout 3s;
proxy_read_timeout 45s;
}
Значения иллюстративные. Проверьте, что они подходят приложению и воркерам. Затем выполните sudo nginx -t && sudo systemctl reload nginx и повторите тот же GET. Для отчёта, которому нужны минуты, обычно удобнее фоновая задача с номером и страницей статуса. Такой подход освобождает веб-воркер и позволяет пользователю проверить результат без повторной тяжёлой операции.
На стенде сервер приложения задерживал заголовки примерно на две секунды. При proxy_read_timeout 1s Nginx вернул 504 и записал upstream timed out. Тот же GET с лимитом в четыре секунды вернул 200.
Первоисточники
Сообщите адрес статьи и фрагмент через контакты редакции.



