В прошлой статье я рассказывал, как устроен мой тренажёр инцидентов изнутри. Сегодня покажу один кейс, седьмой, про 502 Bad Gateway. Он небольшой, но на нём хорошо видно, почему рестарт nginx почти никогда не помогает.

Вводная такая: ночью выкатили релиз, утром магазин отдаёт 502. При этом systemctl status nginx показывает active (running).

502 значит, что nginx запрос принял, передал дальше и нормального ответа не получил. То есть nginx тут свидетель, и начинать надо с его лога:

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

У кейса три варианта поломки, вариант выпадает случайно. Симптом один, а строчка в логе разная.

Приложение слушает не тот порт

connect() failed (111: Connection refused) while connecting to upstream, upstream: "http://127.0.0.1:8080/"

Connection refused: на этом адресе никто не слушает. Смотрим, кто вообще слушает и куда ходит nginx:

sudo ss -tlnp
grep -rn proxy_pass /etc/nginx/

Если после релиза приложение переехало на другой порт, а в конфиге nginx остался старый, правим одну строку, потом sudo nginx -t и sudo systemctl reload nginx. Можно и наоборот, вернуть приложению старый порт. Главное, чтобы совпало.

Сокет есть, но nginx в него не пускают

connect() to unix:/run/shop/app.sock failed (13: Permission denied) while connecting to upstream

Приложение живо и слушает unix‑сокет, но у сокета права 0600, а nginx работает от другого пользователя.

ls -l /run/shop/app.sock
ps -o user= -C nginx | sort -u

Здесь легко попасться: chmod на сокет помогает до следующего перезапуска приложения, потому что сокет создаётся заново. Права надо задавать там, где его создают: в настройках приложения или через UMask= в юните. И проверить, что пользователь nginx входит в группу сокета.

Приложение вообще не запускается

В логе nginx снова Connection refused (или No such file or directory, если nginx ждёт сокет), но ss показывает, что порт никто не занял. Значит, смотрим на само приложение:

systemctl status shop-api
journalctl -u shop-api -n 50 --no-pager

activating (auto-restart) в статусе значит, что сервис падает при старте, а systemd поднимает его снова по Restart=. Причина видна в журнале. В моём кейсе это опечатка в имени переменной в файле из EnvironmentFile=: приложение не находит настройку и выходит.

Мелочь, на которой спотыкаются: после правки файла окружения daemon-reload не нужен, systemd читает его при каждом старте. А если правили сам юнит или drop‑in, без daemon-reload изменения не применятся.

Порядок для любого 502

  1. error.log nginx: что именно ответил upstream.

  2. ss -tlnp или ls -l на сокет: есть ли кто‑то на том конце.

  3. systemctl status и journalctl -u приложения.

Перезапуска nginx в списке нет: при 502 он виноват редко.

А какая самая странная причина 502 была у вас? Если соберётся пара хороших историй, добавлю их в кейс новыми вариантами.

Комментарии (0)