UptimeChecker

Ошибка 502 Bad Gateway: причины и решение

Обложка: Ошибка 502 Bad Gateway: причины и решение

Что такое ошибка 502 Bad Gateway

Ошибка 502 Bad Gateway — это код ответа HTTP, который отдаёт прокси-сервер (шлюз), когда не может получить корректный ответ от вышестоящего сервера (upstream). Говоря проще: сервер, стоящий перед вашим приложением, честно сообщает — «я обратился к бэкенду, но тот не ответил или ответил мусором».

Классическая связка, в которой возникает 502, — это nginx (или Apache в режиме reverse proxy) перед PHP-FPM, Node.js, Python-приложением или другим веб-сервером. Прокси принимает запрос посетителя, перенаправляет его дальше, а назад получает либо ничего, либо ответ, который не может разобрать. Итог — браузеру уходит 502.

Важно понимать: 502 — это всегда проблема на стыке двух серверов. Сам прокси обычно жив и работает, а вот тот, кто за ним, — нет. Это отличает 502 от ошибки 500, где проблема внутри самого приложения, и от 503, где сервер осознанно сообщает о временной недоступности.

Что видит пользователь

Тексты в браузерах различаются, но суть одна:

  • Chrome и Edge: «Ошибка 502 Bad Gateway».
  • Firefox: «502 Bad Gateway».
  • Часто у nginx — собственная страница: «502 Bad Gateway» и строка nginx/1.x.x внизу.

Ошибка 502 Bad Gateway

Почему возникает 502: типичные причины

Причины почти всегда связаны с тем, что бэкенд за прокси либо не запущен, либо не отвечает, либо отвечает неправильно. Разберём по классам.

Бэкенд-процесс не работает

Самая частая причина: PHP-FPM, Node.js или другой обработчик упал, аварийно завершился или не стартовал после перезагрузки сервера. Прокси жив, но ему некому передать запрос — отсюда 502.

Бэкенд слушает не тот порт или сокет

Прокси настроен на один порт или unix-сокет, а приложение слушает другой. Типичный случай после обновления конфигурации: nginx ждёт PHP-FPM на 127.0.0.1:9000, а тот переключился на сокет /run/php/php8.2-fpm.sock.

Таймаут ответа

Бэкенд работает, но отвечает слишком медленно, а у прокси истёк лимит ожидания. Такое бывает при тяжёлых запросах, перегрузке приложения или медленной базе данных.

Бэкенд отвечает мусором

Приложение упало на середине генерации ответа и отдало повреждённые данные, которые прокси не смог разобрать — результат тот же 502.

Таблица причин

Симптом / признак Вероятная причина Решение
502 на всех страницах сразу Бэкенд упал или не запущен Перезапустить PHP-FPM/приложение, проверить статус службы
502 после перезагрузки сервера Служба не стартует автоматически Включить службу в автозагрузку, проверить логи запуска
502 после правки конфигурации nginx Неверный порт/сокет upstream Сверить fastcgi_pass/proxy_pass с реальным адресом бэкенда
502 только на тяжёлых страницах Таймаут прокси, медленный бэкенд Поднять fastcgi_read_timeout, оптимизировать запросы
502 с upstream prematurely closed в логе Бэкенд оборвал соединение Проверить лог бэкенда, увеличить request_terminate_timeout
502 с connect() failed (111: Connection refused) На порту/сокете никто не слушает Запустить бэкенд, исправить адрес в конфигурации
502 периодически, то есть, то нет Перегрузка, нехватка воркеров Увеличить число воркеров, разобраться с нагрузкой
502 с upstream sent too big header Заголовок ответа превысил лимит Поднять буферы fastcgi_buffer_size и fastcgi_buffers

Как диагностировать 502: логи nginx

Лог nginx — первое место, куда нужно смотреть. Запись об ошибке практически всегда говорит, что именно пошло не так.

Типичные записи и их расшифровка

tail -n 50 /var/log/nginx/error.log

Разберём самые частые сообщения.

1. Connection refused:

connect() failed (111: Connection refused) while connecting to upstream

Расшифровка: nginx попытался соединиться с бэкендом по указанному адресу и порту, но там никто не слушает. Значит, либо PHP-FPM/приложение не запущено, либо адрес в конфигурации указан неверно.

2. Преждевременное закрытие соединения:

upstream prematurely closed connection while reading response header from upstream

Расшифровка: соединение установилось, но бэкенд закрыл его, не успев отдать заголовки ответа. Обычно это означает, что приложение упало в процессе обработки запроса — например, фатальная ошибка PHP, которую нужно искать в логах самого PHP-FPM.

3. Таймаут:

upstream timed out (110: Connection timed out) while reading response header from upstream

Расшифровка: nginx ждал ответа дольше установленного лимита. Причина — медленный бэкенд или слишком маленькое значение таймаута.

4. Слишком большой заголовок:

upstream sent too big header while reading response header from upstream

Расшифровка: ответ бэкенда содержит слишком много данных в заголовках (часто из-за множества cookies или крупного заголовка). Лечится увеличением буферов.

Проверяем бэкенд напрямую

Полезно выяснить, жив ли бэкенд сам по себе, в обход прокси. Если он слушает на TCP-порту, проверить можно так:

curl -v http://127.0.0.1:9000/ 2>&1 | head -n 20

Если PHP-FPM работает, вы увидите ответ, начинающийся с попытки установить соединение. Если порт закрыт, curl вернёт Connection refused — значит, бэкенд не запущен или слушает другой порт.

Для unix-сокета проверка выполняется иначе. Сначала убедимся, что сокет существует:

ls -la /run/php/php8.2-fpm.sock

Затем проверим, кто его слушает:

ss -xl | grep php-fpm

Если сокета нет в списке, PHP-FPM не работает — его нужно перезапустить.

Проверяем статус службы PHP-FPM

systemctl status php8.2-fpm

Вывод покажет состояние службы. Строка active (running) — служба работает. Строка failed или inactive означает, что процесс упал или не запущен. В этом случае:

systemctl restart php8.2-fpm

После перезапуска снова проверьте статус — служба должна стать active (running).

Статус службы PHP-FPM

Логи самого бэкенда

Если nginx показывает 502, а сам он исправен, копаем глубже — в логи приложения. Для PHP-FPM это обычно /var/log/php8.2-fpm.log:

tail -n 50 /var/log/php8.2-fpm.log

Там можно увидеть фатальные ошибки скриптов, исчерпание лимитов памяти или нехватку воркеров. Именно эти записи укажут на реальную причину, по которой бэкенд падает или не отвечает.

Конфигурация nginx: частые ошибки

Половина проблем с 502 решается исправлением конфигурации. Рассмотрим типичные места.

Несовпадение адреса в fastcgi_pass

Секция, отвечающая за передачу запроса PHP-FPM, выглядит примерно так:

location ~ \.php$ {
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;
}

Ключевая строка — fastcgi_pass. Её значение должно точно совпадать с тем, как реально запущен PHP-FPM. Если в конфигурации PHP-FPM указан listen = 127.0.0.1:9000, а в nginx — unix:/run/php/php8.2-fpm.sock, запросы будут получать 502. Проверьте директиву listen в /etc/php/8.2/fpm/pool.d/www.conf и приведите адреса в соответствие.

Таймауты

Если 502 возникает только на долгих операциях, поднимите лимиты ожидания:

fastcgi_read_timeout 300;
fastcgi_send_timeout 300;

Значения в секундах. 300 даёт бэкенду пять минут на ответ — этого хватает для большинства тяжёлых операций. Но если запрос стабильно требует больше, лучше разобраться, почему он такой медленный, а не задирать таймауты бесконечно.

Буферы заголовков

Для ошибки upstream sent too big header увеличьте буферы:

fastcgi_buffer_size 16k;
fastcgi_buffers 16 16k;

fastcgi_buffer_size задаёт размер буфера для чтения заголовка ответа, fastcgi_buffers — число и размер буферов для тела ответа. Значения 16k покрывают большинство случаев.

Другие бэкенды: Node.js, Python и проксирование

502 возникает не только в связке nginx + PHP-FPM. Любой reverse proxy перед приложением способен отдать эту ошибку, если приложение не отвечает.

Проксирование HTTP-приложения через proxy_pass

Когда за nginx стоит самостоятельный HTTP-сервер (Node.js на Express, Python на Gunicorn/uWSGI, Go-приложение), используется директива proxy_pass:

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
}

Здесь nginx передаёт запросы приложению, которое слушает порт 3000. Если приложение упало или не стартовало, nginx вернёт 502 — по той же причине «там никто не слушает». Проверить порт можно так:

ss -tlnp | grep 3000

Если порт 3000 не появляется в выводе, приложение не запущено. Запустите его и убедитесь, что адрес в proxy_pass совпадает с тем, где реально слушает приложение.

Проверка HTTPS-бэкенда через openssl

Если за прокси стоит бэкенд, отвечающий по HTTPS, проверить его рукопожатие и сертификат можно напрямую командой openssl, минуя прокси:

openssl s_client -connect 127.0.0.1:443 -servername example.com </dev/null 2>/dev/null | head -n 5

Разбор: s_client устанавливает TLS-соединение с бэкендом, -connect 127.0.0.1:443 — адрес и порт, -servername example.com — имя для SNI, </dev/null закрывает stdin, чтобы команда завершилась сразу после рукопожатия. Если вывод начинается со строки CONNECTED и следом идут данные сертификата — бэкенд отвечает по HTTPS. Если соединение не установилось, проблема на стороне бэкенда, и прокси закономерно отдаёт 502.

Типичный сценарий: приложение под systemd упало

Для приложений, работающих как служба systemd, алгоритм тот же, что и для PHP-FPM. Посмотрите статус и логи:

systemctl status myapp
journalctl -u myapp -n 50

systemctl status myapp покажет, работает ли служба, а journalctl -u myapp -n 50 выведет последние 50 строк её журнала — там будет причина падения (необработанное исключение, ошибка конфигурации, нехватка памяти). Устранив причину и перезапустив службу, вы уберёте и 502.

Связка с другими проблемами: 502 и сертификаты

Иногда 502 появляется в связках, где первопричина не очевидна. Например, при обращении через HTTPS на сайт с проблемным сертификатом часть запросов может не доходить до бэкенда — хотя чаще всего в таких случаях браузер покажет ошибку сертификата, а не 502.

Если вы видите 502 только при обращении по HTTPS, а по HTTP сайт работает, проверьте цепочку: сертификат, его срок действия и корректность настройки SSL на прокси. Проверить сертификат можно отдельно — например, инструментом проверки SSL, который покажет, корректен ли сертификат и не истёк ли он. Просроченный или неверно установленный сертификат на прокси-слое тоже способен ломать передачу запросов к бэкенду.

Профилактика: чтобы 502 не повторялась

  • Включите автозагрузку бэкенда. Убедитесь, что PHP-FPM и приложение стартуют после перезагрузки: systemctl enable php8.2-fpm. Это устраняет самый частый сценарий «перезагрузили сервер — получили 502».
  • Сверяйте конфигурацию при изменениях. После любой правки nginx.conf или пула PHP-FPM проверяйте, что fastcgi_pass/proxy_pass и listen совпадают.
  • Следите за ресурсами. Нехватка памяти или воркеров — частая причина периодических 502. Настройте алерты о превышении порогов.
  • Держите логи под рукой. Разбирайте error.log nginx и логи бэкенда регулярно — многие проблемы дают о себе знать предупреждениями до того, как стать 502.
  • Проверяйте сайт снаружи после релиза. Внутренние проверки не всегда видят то, что видит пользователь. Прогоняйте ключевые страницы через инструмент проверки доступности после каждого развёртывания, чтобы убедиться, что сайт отдаёт 200, а не 502.

Как и в случае с ошибкой 500, внутренний мониторинг инфраструктуры (например, Zabbix) дополняет внешнюю проверку: он следит за здоровьем серверов и служб изнутри и сигнализирует о том, что PHP-FPM упал или перегружен, ещё до того, как это превратится в 502 для посетителей. Внешний же мониторинг отвечает на вопрос, что реально видит пользователь, открывая сайт из интернета.

Соседние ошибки 5xx

  • Ошибка 504 Gateway Timeout — похожа на 502, но причина строго в том, что бэкенд не уложился в отведённое время. Если вместо 502 вы видите 504, дело почти наверняка в таймаутах и медленном бэкенде, а не в том, что он упал.

Коротко

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

Диагностика строится на логах nginx — записи Connection refused, upstream prematurely closed и upstream timed out прямо указывают на характер проблемы. Дальше проверяем сам бэкенд: статус службы systemctl status php8.2-fpm, наличие unix-сокета, прямые запросы через curl. После исправления сверяем конфигурацию и проверяем сайт снаружи — инструмент проверки доступности UptimeChecker покажет, какой код статуса сервер отдаёт реальным посетителям.