
Ошибка 504 Gateway Timeout в Nginx: диагностика без догадок
Разбираем 504 Gateway Timeout: находим медленный участок между Nginx и приложением, сверяем журналы и время ответа, проверяем базу и настраиваем таймаут только по фактам.
Содержание
504 Gateway Timeout означает, что Nginx принял запрос как шлюз или reverse proxy, передал его следующему серверу, но не получил ответ вовремя. Следующим сервером может быть приложение, PHP-FPM, другой прокси или внешний сервис.
Первая мысль часто — увеличить таймаут. Это оправдано только для операции, которая действительно должна выполняться долго. Если запрос замедлился из-за базы данных, зависшего процесса или внешнего API, большой таймаут лишь заставит посетителя ждать дольше и удержит ресурсы сервера.
Где именно истекает время ожидания
Публичный запрос обычно проходит цепочку:
- браузер соединяется с Nginx;
- Nginx отправляет запрос приложению;
- приложение обращается к базе, файлам или внешнему API;
- ответ возвращается тем же путём.
Код 504 сообщает, что один сервер ждал другой. Он не доказывает, что виноват Nginx. Важно выяснить, какой компонент ждал и на какой операции остановилось приложение.
Не путайте 504 с 502. При 502 Nginx обычно не может установить соединение или получает некорректный ответ. При 504 соединение могло состояться, но данные не пришли в допустимый интервал. Точную ветку задаёт строка error log.
Воспроизведите один запрос и измерьте время
С локального компьютера запросите проблемный URL. Замените адрес своим:
curl -sS -o /dev/null \
-w 'status=%{http_code} connect=%{time_connect}s first_byte=%{time_starttransfer}s total=%{time_total}s\n' \
--max-time 70 https://example.com/report/
time_connect показывает время установки соединения, time_starttransfer — ожидание первого байта ответа, а time_total — полную длительность. Если соединение устанавливается быстро, но первый байт приходит только перед 504, задержка находится после принятия запроса Nginx.
Запишите время запуска, URL и статус. Не запускайте параллельные циклы на production: они могут усилить перегрузку и затруднить чтение журналов.
Найдите соответствующую запись Nginx
На VPS с правами sudo прочитайте активную конфигурацию и последние ошибки. Обе команды диагностические: они не перезапускают Nginx и не меняют его файлы:
sudo nginx -T 2>/dev/null | grep -E 'error_log|access_log|proxy_pass|fastcgi_pass|timeout'
sudo tail -n 100 /var/log/nginx/error.log
Команды ничего не меняют. Путь журнала может отличаться, поэтому ориентируйтесь на nginx -T. Не публикуйте весь вывод конфигурации без проверки: там бывают внутренние адреса.
Для 504 важны формулировки вроде:
upstream timed out ... while reading response header from upstream— Nginx не дождался заголовков ответа;while reading upstream— пауза возникла уже при чтении тела;while connecting to upstream— не удалось вовремя установить соединение;while sending request to upstream— задержка возникла при передаче запроса.
В строке также видны upstream, URI и адрес клиента. Они связывают ошибку с конкретным приложением и маршрутом.
Запросите приложение без публичного прокси
Если в proxy_pass указан http://127.0.0.1:3000, выполните на VPS запрос к тому же маршруту:
curl -sS -o /dev/null \
-w 'status=%{http_code} first_byte=%{time_starttransfer}s total=%{time_total}s\n' \
--max-time 65 http://127.0.0.1:3000/report/
Замените порт и путь на реальные. Если локальный запрос тоже медленный, Nginx лишь фиксирует задержку приложения. Если он быстрый, сравните заголовки, параметры запроса, авторизацию и маршрут: тестовый /health не заменяет тяжёлый /report/.
Для Unix-сокета или PHP-FPM используйте журнал соответствующей службы, потому что обычный HTTP-запрос к сокету FastCGI не подходит. Посмотрите состояние и события за тот же интервал:
systemctl status myapp.service --no-pager
sudo journalctl -u myapp.service --since "15 minutes ago" --no-pager
Подставьте настоящее имя службы. Ищите завершение процесса, очередь запросов, таймаут клиента базы или внешнего API и ошибки памяти.
Проверьте, где приложение тратит время
Медленный запрос чаще связан не с вычислением HTML, а с зависимостью:
- запрос к базе данных не использует индекс или ждёт блокировку;
- внешний API не отвечает, а клиент не имеет короткого таймаута;
- сетевое хранилище задерживает чтение файла;
- очередь воркеров заполнена долгими задачами;
- процесс испытывает нехватку памяти или процессорного времени;
- в одном HTTP-запросе выполняется экспорт, импорт или генерация отчёта.
Смотрите журнал приложения и метрики именно во время медленного запроса. Средняя загрузка сервера после события ничего не доказывает. Для базы полезны журнал медленных запросов и план выполнения; для внешнего API — измеренная длительность и собственный таймаут клиента.
Долгую операцию, результат которой не нужен немедленно, лучше вынести в фоновую задачу. Пользователь получает идентификатор операции, а интерфейс позже запрашивает её состояние. Это уменьшает число длительных соединений и делает сбой повторяемым.
Разберитесь, какой таймаут сработал
В Nginx разные директивы отвечают за разные паузы. Для HTTP-прокси чаще встречаются:
proxy_connect_timeout— ожидание соединения с upstream;proxy_send_timeout— допустимая пауза при отправке запроса;proxy_read_timeout— допустимая пауза между операциями чтения ответа.
proxy_read_timeout не является общим секундомером всей страницы. Если upstream периодически передаёт данные, длительный ответ может не нарушить этот таймаут. Поэтому значение выбирают по характеру конкретной операции, а не по случайной рекомендации.
Пример отдельного правила для измеренного долгого отчёта:
location = /report/export {
proxy_pass http://127.0.0.1:3000;
proxy_connect_timeout 5s;
proxy_read_timeout 90s;
}
Точное совпадение location = ограничивает увеличенный таймаут одним маршрутом. 90s здесь лишь пример: выберите значение после измерения штатной длительности и с учётом числа одновременных запросов. Не увеличивайте таймаут для всего сайта без необходимости.
Перед правкой сохраните текущий конфигурационный файл. Затем проверьте синтаксис и примените reload:
sudo nginx -t
sudo systemctl reload nginx
При ошибке nginx -t reload не выполняйте. Восстановите копию или исправьте указанную строку.
Когда причина находится между серверами
Если Nginx и приложение работают на разных узлах, проверьте маршрут от прокси к upstream, а не доступность приложения из браузера администратора. На узле Nginx выполните один запрос к внутреннему адресу и сравните его время с локальным запросом на сервере приложения.
Таймаут соединения может появиться из-за firewall, неверного маршрута, перегруженного балансировщика или недоступного адреса. Проверяйте конкретный порт и протокол. Ping не подтверждает, что HTTP-служба принимает соединения.
Подтвердите исправление под контролируемой нагрузкой
После устранения причины повторите тот же запрос и сравните first_byte и total. Затем проверьте error log и состояние приложения. Успех означает:
- исходный URL возвращает ожидаемый статус;
- время ответа укладывается в заданный предел;
- в журнале нет нового
upstream timed out; - соседние быстрые запросы не замедлились;
- при отмене или сбое долгой операции система не оставляет повреждённые данные.
Если изменение не помогло, верните прежнее значение таймаута и продолжите поиск по журналу приложения. Для ошибок соединения используйте диагностику 502 Bad Gateway, а для настройки наблюдаемости — руководство по журналам Nginx и healthcheck приложения.
Источники
Самопроверка
Проверьте, что материал усвоен
Ответьте на все вопросы. Результат сохранится только в этом браузере и будет учтён в статистике прочитанных материалов.
Разбираем коротко
Частые вопросы
Что означает 504 Gateway Timeout в Nginx?
Nginx работал как шлюз или прокси, но не дождался своевременного ответа от следующего сервера. Причину ищут в приложении, базе данных, внешнем API, сети между узлами и только затем в значениях таймаутов.
Чем ошибка 504 отличается от 502?
504 указывает на несвоевременный ответ от следующего сервера, а 502 — на некорректный ответ или ошибку соединения с ним. Журнал Nginx даёт более точную формулировку для конкретного запроса.
Нужно ли сразу увеличивать proxy_read_timeout?
Нет. Увеличение оправдано для заведомо долгой операции, которая исправно выполняется. Оно не устраняет медленный запрос к базе, зависший процесс, нехватку ресурсов или недоступный внешний сервис.


