Перейти к содержанию
Innovialabs

502 Bad Gateway и 504 Gateway Timeout в Nginx: причины и решение

Практика4 мин

Коротко

502 значит, что Nginx не получил корректный ответ от бэкенда (он упал, не слушает сокет или нет прав), а 504 — что бэкенд не ответил вовремя; причину почти всегда показывает error.log.

Чем отличаются 502 и 504

Nginx в роли reverse proxy сам страницу не генерирует — он передаёт запрос upstream-приложению (PHP-FPM, Node.js, Python, Go) и возвращает его ответ.

  • 502 Bad Gateway — Nginx не смог получить нормальный ответ: соединение отклонено, сокет не найден, процесс упал посреди ответа, заголовки ответа не влезли в буфер.
  • 504 Gateway Timeout — соединение есть, но бэкенд не уложился в отведённое время.

Проще говоря: 502 — «бэкенда нет или он ответил мусором», 504 — «бэкенд есть, но слишком медленный».

Шаг 1. Прочитайте error.log

Не меняйте конфиг наугад. Сначала откройте лог ошибок:

sudo tail -n 50 /var/log/nginx/error.log

Путь может отличаться — проверьте директиву error_log в конфиге. Типичные строки и что они означают:

Сообщение в логеПричина
connect() failed (111: Connection refused)приложение не запущено или слушает другой порт
connect() to unix:... failed (2: No such file or directory)неверный путь к сокету или PHP-FPM не запущен
connect() to unix:... failed (13: Permission denied)у пользователя Nginx нет прав на сокет
upstream prematurely closed connectionпроцесс упал или был убит во время ответа
upstream sent too big headerзаголовки ответа не помещаются в буфер
upstream timed out (110: Connection timed out)бэкенд отвечает дольше таймаута, это 504

Шаг 2. Проверьте процесс и сокет upstream

Убедитесь, что приложение живо и слушает именно тот адрес, что указан в proxy_pass или fastcgi_pass:

systemctl status php8.2-fpm        # или имя вашего сервиса
ss -ltnp | grep 3000               # TCP-порт Node.js
ls -l /run/php/                    # unix-сокеты PHP-FPM
curl -I http://127.0.0.1:3000      # запрос в обход Nginx

Если curl напрямую не отвечает — проблема не в Nginx. Смотрите логи самого приложения: journalctl -u имя-сервиса.

Частая ошибка — несовпадение адресов: Nginx стучится на 127.0.0.1:3000, а приложение слушает localhost только по IPv6 или другой порт. Ещё одна — после обновления PHP имя сокета изменилось, а в конфиге остался старый.

Шаг 3. Права на сокет

При Permission denied проверьте, от какого пользователя работает Nginx (user в nginx.conf) и кто владелец сокета. В конфиге пула PHP-FPM задайте:

listen.owner = www-data
listen.group = www-data
listen.mode = 0660

Перезапустите PHP-FPM. Если включён SELinux, отказ может приходить от него — тогда смотрите audit-лог.

Шаг 4. Таймауты (лечение 504)

Сначала выясните, почему запрос долгий: медленный SQL, внешний API, тяжёлый отчёт. Повышать таймаут стоит только для действительно долгих операций — и лучше точечно, для конкретного location:

location /reports/ {
    proxy_connect_timeout 10s;
    proxy_read_timeout    120s;
    proxy_send_timeout    120s;
    proxy_pass http://127.0.0.1:3000;
}

Для PHP-FPM аналог — fastcgi_read_timeout. Учтите, что у самого PHP есть max_execution_time и request_terminate_timeout в пуле: если они меньше таймаута Nginx, процесс будет убит раньше, и вы получите 502 вместо 504.

Долгие задачи (импорт, генерация файлов) правильнее выносить в фоновую очередь, а пользователю отдавать статус.

Шаг 5. Буферы

Ошибка upstream sent too big header обычно возникает из-за больших cookie или множества заголовков. Увеличьте буферы:

proxy_buffer_size        16k;
proxy_buffers            8 16k;
proxy_busy_buffers_size  32k;
# для PHP-FPM
fastcgi_buffer_size      32k;
fastcgi_buffers          16 16k;

Заодно проверьте, не раздувает ли приложение cookie без необходимости.

Шаг 6. Падения PHP-FPM и Node.js

Если 502 появляются под нагрузкой, а потом проходят — бэкенд не справляется:

  • PHP-FPM: в логе пула ищите server reached pm.max_children setting. Значит, все воркеры заняты. Увеличивайте pm.max_children с оглядкой на память: каждый воркер занимает её отдельно.
  • Node.js: необработанное исключение роняет процесс целиком. Запускайте приложение под менеджером процессов (systemd, PM2, Docker с restart), чтобы он поднимался автоматически, и ищите причину в логах.
  • OOM killer: проверьте dmesg | grep -i kill. Если ядро убивает процесс из-за нехватки памяти, нужны либо оптимизация, либо больше RAM.

После любой правки проверяйте конфиг и перезагружайте его без остановки сервера:

sudo nginx -t && sudo systemctl reload nginx

Чек-лист

  1. Прочитать error.log и найти точную ошибку.
  2. Проверить, что upstream запущен и отвечает напрямую.
  3. Сверить адрес, порт или путь к сокету.
  4. Проверить права на unix-сокет.
  5. Для 504 — найти медленное место, затем точечно поднять таймаут.
  6. Для «too big header» — увеличить буферы.
  7. Проверить лимиты воркеров и OOM killer.

Частые вопросы

Чаще всего бэкенд не выдерживает пиковую нагрузку: заканчиваются воркеры PHP-FPM, процесс Node.js падает и перезапускается или его убивает OOM killer. Сопоставьте время ошибок в error.log с логами приложения и dmesg.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.