
Ошибка 502 Bad Gateway в Nginx: что проверить и как исправить
Пошаговая диагностика 502 Bad Gateway: читаем error log Nginx, проверяем приложение, порт или Unix-сокет, контейнеры и только затем исправляем причину.
Содержание
502 Bad Gateway в Nginx означает, что Nginx принял запрос посетителя, попытался передать его следующему серверу и не получил корректный ответ. Следующим сервером, или upstream, может быть Node.js-приложение, Python-сервис, PHP-FPM, другой веб-сервер либо контейнер.
Ошибка не говорит, что Nginx нужно переустановить. Чаще служба приложения остановлена, слушает другой адрес, не принимает соединение через Unix-сокет или завершается во время запроса. Сначала сохраните сообщение из журнала: оно сокращает диагностику с десятков догадок до нескольких проверок.
Как устроен запрос, который заканчивается 502
Reverse proxy — сервер, который принимает публичный запрос и передаёт его внутреннему приложению. Пользователь обращается к https://example.com, Nginx завершает HTTPS-соединение и по директиве proxy_pass отправляет запрос, например, на http://127.0.0.1:3000.
У этой цепочки три отдельные части:
- Браузер соединяется с Nginx.
- Nginx соединяется с upstream.
- Upstream формирует корректный HTTP-ответ.
Код 502 обычно означает, что первая часть уже работает, а сбой произошёл во второй или третьей. Код 504 похож, но точнее указывает на несвоевременный ответ. Различие важно: увеличение таймаута не исправит службу, которая вообще не запущена.
Запишите один воспроизводимый запрос
С локального компьютера запросите проблемный URL и сохраните заголовки:
curl -sS -D - -o /dev/null https://example.com/api/health
Запишите точное время, URL и метод. Проверьте также главную страницу. Если 502 возникает только на /api/, вероятен отдельный location или маршрут приложения. Если он появляется на всех динамических страницах, проблема может затрагивать всю службу upstream.
Не запускайте нагрузочный цикл на production. Для поиска причины достаточно одного запроса, который можно сопоставить с журналами.
Прочитайте сообщение Nginx за то же время
На VPS с правами sudo найдите активные журналы и последние сообщения error log. Команды ничего не меняют: первая читает собранную конфигурацию, вторая показывает конец стандартного файла журнала:
sudo nginx -T 2>/dev/null | grep -E 'error_log|access_log|proxy_pass|fastcgi_pass'
sudo tail -n 100 /var/log/nginx/error.log
Вывод nginx -T может содержать внутренние адреса и параметры конфигурации, поэтому не публикуйте его целиком. Путь error log берите из активной конфигурации.
Сообщение рядом с запросом обычно сразу задаёт ветку проверки:
connect() failed (111: Connection refused)— на указанном TCP-порту никто не принимает соединение;connect() to unix:... failed (13: Permission denied)— Nginx не может пройти к Unix-сокету или открыть его;No such file or directory— сокет не создан либо в конфигурации указан другой путь;upstream prematurely closed connection— приложение приняло соединение, но закрыло его до полного ответа;upstream sent invalid header— приложение отправило данные, которые Nginx не смог разобрать как корректные HTTP-заголовки;upstream timed out— работающий upstream не передал данные в установленный интервал.
Unix-сокет — специальный файл для обмена между процессами на одном сервере. TCP-порт делает то же через сетевой адрес вроде 127.0.0.1:3000. Проверки для них различаются.
Если приложение должно слушать TCP-порт
Предположим, в конфигурации находится proxy_pass http://127.0.0.1:3000;. Сначала проверьте, существует ли слушающий порт:
sudo ss -ltnp
systemctl status myapp.service --no-pager
sudo journalctl -u myapp.service --since "15 minutes ago" --no-pager
В ss должна быть строка с 127.0.0.1:3000 или другим ожидаемым адресом. systemctl status показывает, работает ли служба, а journalctl — почему она завершилась или перезапускается. Замените myapp.service настоящим именем своего unit-файла.
Затем обратитесь к приложению напрямую с самого VPS:
curl -v --max-time 5 http://127.0.0.1:3000/health
Успешный ответ подтверждает, что процесс доступен без Nginx. Статус самого health endpoint может быть 200 или иной предусмотренный приложением, но соединение не должно завершаться Connection refused или таймаутом.
Если порт не слушается, читайте журнал приложения. Частые причины — ошибка конфигурации, занятый порт, недоступная база данных, отсутствующая переменная окружения или аварийное завершение по памяти. Исправляйте конкретное сообщение. Если приложение слушает 127.0.0.1:3001, а Nginx обращается к 3000, согласуйте адрес в одном месте и сохраните прежнюю конфигурацию для отката.
Если используется Unix-сокет
Путь можно увидеть в proxy_pass или fastcgi_pass. Проверьте наличие сокета, владельца и каталоги до него:
sudo ss -lxnp
namei -l /run/myapp/app.sock
sudo -u www-data test -w /run/myapp/app.sock
echo $?
Код 0 после test означает, что пользователь www-data имеет требуемый доступ к сокету. Ему также нужен проход по родительским каталогам. Не лечите Permission denied режимом 777: правильнее настроить пользователя и группу сокета в самой службе приложения или в конфигурации пула PHP-FPM.
У файлов в /run короткая жизнь: каталог обычно создаётся заново при загрузке. Ручной chmod может исчезнуть после перезапуска. Исправление должно находиться в unit-файле systemd, параметрах runtime directory или настройке владельца сокета. После правки перезапустите только соответствующую службу и снова проверьте namei.
Сверьте протокол и адрес в proxy_pass
Даже работающий порт вернёт ошибку, если Nginx разговаривает с ним не по тому протоколу. Пример минимального HTTP-upstream:
location /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
Здесь http:// описывает соединение между Nginx и приложением. Публичный сайт при этом может работать по HTTPS. Не заменяйте http:// на https:// только потому, что браузер открывает HTTPS: внутренний сервис должен действительно поддерживать TLS.
Проверьте активную конфигурацию, а не только файл, который вы помните. После минимальной правки выполните:
sudo nginx -t
sudo systemctl reload nginx
Если проверка синтаксиса неуспешна, reload выполнять нельзя. Верните копию изменённого файла и разберите номер строки из сообщения nginx -t.
Когда приложение работает в Docker Compose
Посмотрите состояние контейнеров и последние сообщения проекта из каталога с его compose.yaml:
docker compose ps
docker compose logs --tail 100 app
Замените app именем сервиса. Если Nginx запущен на хосте, он обращается к опубликованному на loopback порту, например 127.0.0.1:3000. Если Nginx находится в том же Compose-проекте, он обычно использует имя сервиса и внутренний порт, например http://app:3000, а не localhost: внутри контейнера localhost указывает на этот же контейнер.
Статус Restarting означает, что процесс завершается и оркестратор запускает его снова. Не увеличивайте таймаут Nginx — сначала устраните причину в логе контейнера. Подробная последовательность есть в руководстве по диагностике Docker Compose.
Не маскируйте причину таймаутом
proxy_read_timeout задаёт допустимую паузу между операциями чтения ответа upstream, а не максимальную длительность всей страницы. Увеличение значения оправдано только когда приложение штатно выдаёт долгий потоковый ответ и журнал подтверждает именно таймаут чтения.
Если обычная страница внезапно стала отвечать минуту, сначала проверьте нагрузку, запросы базы данных, внешние API и очередь приложения. Большой таймаут удержит соединения дольше, но не сделает backend быстрее.
Проверьте исправление с двух сторон
После изменения выполните локальный запрос к приложению, затем публичный запрос через Nginx:
curl -sS -D - -o /dev/null http://127.0.0.1:3000/health
curl -sS -D - -o /dev/null https://example.com/api/health
sudo tail -n 20 /var/log/nginx/error.log
Успех означает, что upstream отвечает напрямую, внешний URL больше не возвращает 502, а в error log не появляется новая запись для тестового запроса. Проверьте ещё один обычный маршрут приложения, чтобы health endpoint не оказался единственным работающим адресом.
Если правка не помогла, верните прежний proxy_pass или конфигурацию службы, проверьте синтаксис и примените reload. Не складывайте несколько догадок в один релиз: иначе вы не узнаете, какое изменение повлияло на результат.
Для постоянного наблюдения добавьте поля upstream в access log по инструкции про журналы Nginx. Если конфигурация reverse proxy ещё не понятна, начните с материала о передаче запроса приложению.
Источники
Самопроверка
Проверьте, что материал усвоен
Ответьте на все вопросы. Результат сохранится только в этом браузере и будет учтён в статистике прочитанных материалов.
Разбираем коротко
Частые вопросы
Что означает ошибка 502 Bad Gateway?
Прокси или шлюз получил некорректный ответ от следующего сервера, к которому обратился для выполнения запроса. В схеме с Nginx этим следующим сервером обычно является приложение или PHP-FPM.
Поможет ли увеличение proxy_read_timeout при 502?
Только если журнал подтвердил паузу чтения от работающего upstream. Таймаут не запустит остановленную службу, не исправит неверный порт, права Unix-сокета или несовпадение HTTP и HTTPS.
Почему нельзя сразу перезапустить Nginx и приложение?
Перезапуск может временно скрыть симптом и уничтожить полезное состояние процесса. Сначала сохраните время ошибки и журналы, проверьте службу и доступность upstream, затем перезапускайте только подтверждённо зависший компонент.


