После deploy главная открывается, а форма или каталог отвечает 502. Через минуту код меняется на 504. Эти ошибки похожи для пользователя, но чинятся по-разному: в первом случае приложение часто не принимает соединение или возвращает некорректный ответ, во втором Nginx ждёт данные слишком долго.
Первое, что я бы сделал, — воспроизвёл один запрос и записал точное время, URL и код. Если в конфигурации есть request ID, сохраните его. Без этого в error.log легко разобрать чужой запрос.
Проверьте конфигурацию и listener
# Конфигурация Nginx без reload
sudo nginx -t
# Последние ошибки proxy
sudo tail -n 100 /var/log/nginx/error.log
sudo journalctl -u nginx --since '-10 minutes' --no-pager
# Кто слушает TCP-порты
sudo ss -lntp
# Прямой запрос к приложению, минуя публичный домен
curl -sS -D - -o /dev/null http://127.0.0.1:<app-port>/api/health
# Состояние сервиса приложения
sudo systemctl status <app-service> --no-pager
Подставьте фактический порт и имя службы из deployment-конфигурации. Не копируйте пример как есть. Запрос к публичному домену снова попадёт в Nginx и не проверит upstream напрямую.
Читайте глагол в error.log
| Фрагмент | Что произошло | Куда смотреть |
|---|---|---|
| connect() failed / refused | Соединение не установлено | Процесс, порт, socket, firewall |
| upstream timed out while reading | Ответ не пришёл вовремя | Лог приложения, БД, внешний API |
| no live upstreams | Нет доступного backend | upstream group и health |
| invalid header | Получен некорректный HTTP-ответ | Протокол, порт, приложение |
Рабочий алгоритм
- Воспроизведите один проблемный URL и зафиксируйте время.
- Найдите строку error.log с тем же upstream и URI.
- Запустите
nginx -t; не делайте reload при ошибке синтаксиса. - Проверьте listener через
ss -lntpи владельца процесса. - Вызовите health endpoint напрямую.
- Если прямой запрос медленный, сопоставьте время с логом приложения, СУБД и внешних API.
- Меняйте timeout только после измерения нормальной и аварийной длительности.
PASS и FAIL
- PASS:
nginx -tподтверждает конфигурацию до reload. - PASS: приложение слушает ожидаемый адрес, а health endpoint быстро отвечает.
- PASS: строка error.log связана с одним запросом и одним upstream.
- FAIL: порт в
proxy_passне совпадает с listener после deploy. - FAIL: timeout увеличили, не найдя медленный запрос.
- FAIL: рестарт скрывает проблему, но 504 возвращается под нагрузкой.
Где чаще всего теряют время
Перезапускают Nginx. Proxy исправен, а Node, PHP-FPM или другой backend упал. Смотрите владельца listener и журнал приложения.
Проверяют не тот путь. Корень отвечает 200 из кэша, а проблемный API идёт в другой upstream. Тестируйте исходный URI.
Ставят огромный таймаут. Медленный SQL теперь держит соединение дольше, очередь растёт, а причина остаётся.
Не проверяют память. Процесс убит OOM, supervisor поднял его снова, и ошибка кажется случайной. Сопоставьте время с kernel log и мониторингом.
Чек-лист после исправления
- Прямой health-check стабильно отвечает.
- Nginx направляет запрос на фактический порт или socket.
- Логи proxy и приложения связаны request ID.
- Под нагрузкой нет роста 502/504.
- Таймауты документированы и не скрывают медленный запрос.
- Rollback release проверен до следующего deploy.
Что проверить, если ошибка появляется только под нагрузкой
Одиночный health-check может отвечать за 20 миллисекунд, а под десятью параллельными запросами приложение упирается в пул БД. Поэтому после базовой проверки сопоставьте 504 с числом активных запросов, очередью соединений и временем самого медленного endpoint. Не запускайте тяжёлый нагрузочный тест на production без согласованного окна.
Снимите короткий профиль на существующем трафике: HTTP-код, URI, upstream response time и request ID. В приложении запишите длительность обработчика и SQL. Разница между временем Nginx и временем приложения покажет участок ожидания. Если приложение завершило запрос быстро, а proxy продолжал ждать, проверяйте сеть, буферизацию и протокол.
После релиза проверьте четыре соответствия
proxy_passуказывает на порт нового процесса.- Процесс запущен из текущего release, а не из старого каталога.
- Health endpoint проверяет критичную зависимость, но не выполняет тяжёлый запрос.
- Reload Nginx сделан только после успешного
nginx -t.
Если используется Unix socket, проверьте путь, владельца и права. Приложение могло создать новый socket в другом каталоге, пока Nginx продолжает обращаться к старому. PASS: proxy-пользователь может подключиться к актуальному socket. FAIL: файл существует, но принадлежит другому пользователю или исчезает при restart.
После исправления смотрите не только статус страницы. Ошибка могла уйти, а p95 времени ответа остаться около timeout. Такой запас закончится следующим всплеском нагрузки.
Что делать, если не помогло
Соберите один пакет доказательств: request ID, строку Nginx, прямой health-check, состояние процесса и метрики CPU, памяти, пула соединений БД за ту же минуту. Если upstream быстрый напрямую, проверяйте адрес в proxy_pass, DNS и сокет. Если он медленный напрямую, Nginx уже не главный подозреваемый. После исправления пройдите приёмочный чек-лист сайта и отдельно проверьте canonical после релиза. CTR1 может проверить и доработать production-сайт, сохранив рабочий rollback.



