502 Bad Gateway и 504 Gateway Timeout в Nginx: причины и решение
Практика4 минРедакция Innovialabs
Коротко
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
Чек-лист
- Прочитать
error.logи найти точную ошибку. - Проверить, что upstream запущен и отвечает напрямую.
- Сверить адрес, порт или путь к сокету.
- Проверить права на unix-сокет.
- Для 504 — найти медленное место, затем точечно поднять таймаут.
- Для «too big header» — увеличить буферы.
- Проверить лимиты воркеров и OOM killer.