Nginx 502: upstream prematurely closed connection — Решение сбоя
Nginx отправляет запрос в бэкенд, но целевое приложение аварийно закрывает TCP-сокет до того, как успевает вернуть валидный HTTP-заголовок ответа. В логах Nginx: peer closed connection in status 502 / upstream prematurely closed connection while reading response header.
| Фактор отказа | Что происходит на бэкенде | Результат в Nginx |
|---|---|---|
| Segmentation Fault (Segfault) | Процесс упал в core dump из-за ошибки памяти | TCP FIN отправлен мгновенно |
| System OOM Killer | Ядро Linux уничтожило бэкенд (SIGKILL) | Мгновенный обрыв соединения |
| HTTP/Keep-Alive Race | Бэкенд закрыл idle-соединение по таймауту | Повторный reuse сокета завершился сбросом |
- Ошибка проявляется хаотично или под определенными «тяжелыми» POST-запросами.
- В логах бэкенда (PHP-FPM, Gunicorn, Puma) видны сообщения:
child exited on signal 11 (SIGSEGV)или процесс внезапно перезапускается с новым PID.
- Проверьте системный журнал ядра на предмет падений процессов и работы OOM Killer:
sudo dmesg -T | grep -E -i "segfault|oom|killed process" sudo journalctl -k --since "10 minutes ago" - Изучите логи самого бэкенд-сервера (PHP-FPM, Uvicorn, Node):
# Для PHP-FPM: sudo tail -n 50 /var/log/php*-fpm.log # Для Systemd юнита: sudo journalctl -u <backend> -n 50 --no-pager - Если проблема вызвана race condition в keepalive соединениях между Nginx и бэкендом, настройте корректный блок
upstream:upstream my_backend { server 127.0.0.1:8000; keepalive 32; keepalive_timeout 60s; } server { location / { proxy_pass http://my_backend; proxy_http_version 1.1; proxy_set_header Connection ""; } } - Если процесс бэкенда падает по Segfault, отключите сбойные расширения (например, Xdebug, OPcache JIT или сторонние модули C/C++).
- Перезапустите стек сервисов:
sudo systemctl restart <backend> nginx.
Частые вопросы (FAQ)
Почему Nginx пишет prematurely closed connection?
Потому что бэкенд разорвал TCP-сессию (отправил RST или FIN пакет) до отправки хотя бы одного байта HTTP-заголовка ответа.
Как проверить, не завершается ли процесс из-за OOM?
Выполните dmesg | grep -i 'killed process'. Если память процесса превысила лимит, ядро завершает его по SIGKILL, что вызывает данный сбой в Nginx.
Поможет ли увеличение proxy_read_timeout?
Нет, так как соединение не зависает по тайм-ауту, а активно и принудительно обрывается со стороны самого бэкенда.
Зачем указывать proxy_set_header Connection '' при keepalive?
По умолчанию Nginx выставляет заголовок 'Connection: close'. Очистка заголовка необходима для корректной работы постоянных Keep-Alive соединений по протоколу HTTP/1.1.