502 Bad Gateway: что сломалось за прокси и как это найти
502 Bad Gateway означает, что прокси перед вашим сайтом запросил у бэкенда ответ и получил что-то невалидное, либо вообще ничего. Прокси работает правильно; он сообщает, что то, что стоит за ним, недоступно, падает или говорит не на том протоколе.
Кто возвращает 502 и почему
RFC 9110 определяет 502 для сервера, выступающего шлюзом или прокси, который получил невалидный ответ от внутреннего сервера, к которому обращался, пытаясь выполнить запрос. В любом современном стеке есть хотя бы один такой переход: nginx или Apache перед сервером приложения, балансировщик нагрузки перед флотом серверов, CDN перед вашим источником, либо все три сразу.
Эта многослойность - ключ к чтению 502. Компонент, который ответил, достаточно здоров, чтобы сформировать страницу ошибки. Компонент за ним - нет. Так что 502 всегда делит ваш стек на рабочую половину и сломанную, и ваша задача - определить, где проходит граница.
Соседние коды говорят о более узких вещах. 504 Gateway Timeout означает, что бэкенд был доступен, но слишком медленным. 500 означает, что сам бэкенд выполнился и выбросил ошибку. 502 означает, что бэкенд дал плохой ответ либо не дал никакого. Полное сравнение - в обзоре 5xx.
Распространенные причины
- Процесс бэкенда не запущен. Упавший сервер приложения, остановленный пул PHP-FPM, контейнер, который завершился или провалил проверку здоровья. Прокси подключается к порту, на котором никто не слушает.
- Бэкенд упал посреди запроса. Убийство из-за нехватки памяти или ошибка сегментации закрывает соединение до того, как завершились заголовки ответа.
- Неверный адрес или порт вышестоящего сервера. Конфигурация, указывающая на старый порт после изменения, либо на хост, который больше не разрешается.
- Несовпадение протокола. Прокси говорит обычным HTTP с портом, ожидающим TLS, или наоборот. Байты неразбираемы, поэтому прокси называет ответ невалидным.
- Слишком большие заголовки ответа. Слишком большая cookie или необычно длинный заголовок превышают буфер прокси, и ответ отклоняется, а не передается дальше.
- Несовпадение keep-alive. Прокси переиспользует простаивающее соединение, которое бэкенд уже закрыл, что дает спорадические 502 при в остальном нормальной нагрузке.
- Перезапуски и деплои. Любое окно, когда старый процесс уже остановился, а новый еще не принимает соединения.
- Все бэкенды нездоровы. Балансировщику нагрузки без единого проходящего проверку участника некуда отправить запрос.
Чтение лога прокси, которое обычно и завершает расследование
Код состояния общий, а строка лога прокси - конкретная. Для nginx стоит узнавать такие сообщения:
[error] connect() failed (111: Connection refused) while connecting to upstream,
upstream: "http://127.0.0.1:8080/"
[error] upstream prematurely closed connection while reading response header
from upstream
[error] recv() failed (104: Connection reset by peer) while reading response
header from upstream
[error] upstream sent too big header while reading response header from upstream
[error] no live upstreams while connecting to upstream
Каждое указывает на свое:
connect() failed (111: Connection refused). На этом адресе и порту никто не слушает. Бэкенд остановлен, привязан к другому интерфейсу либо находится на другом порту, чем указано в конфигурации.upstream prematurely closed connection. Бэкенд принял запрос, а затем упал или повис, не завершив ответ. Ищите падения, убийства из-за нехватки памяти или таймаут воркера внутри приложения, а не в nginx.connection reset by peer. Похоже, но соединение было активно сброшено. Часто это файрвол посередине либо бэкенд, закрывший пуловое соединение, которое прокси все еще считал открытым.upstream sent too big header. Проблема размера буфера в прокси, а не сбой в бэкенде. Ответ валиден, но больше, чем настроен вмещать прокси.no live upstreams. Проверки здоровья пометили каждый бэкенд как недоступный.
Как это исправить
- Проверьте бэкенд напрямую, в обход прокси. С хоста прокси запросите сам вышестоящий адрес:
200 здесь при 502 на публичном URL означает, что проблема в конфигурации прокси либо в связи между ними двумя. Отклоненное соединение означает, что бэкенд действительно лежит.curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/ - Проверьте, что бэкенд запущен и слушает на адресе, который ожидает прокси. Привязка к
127.0.0.1, когда прокси обращается к адресу контейнера, - частая причина. - Прочитайте лог ошибок прокси и сопоставьте сообщение со списком выше, прежде чем менять какую-либо конфигурацию.
- Затем прочитайте лог бэкенда. Падение, убийство из-за нехватки памяти или таймаут воркера в ту же секунду подтверждает случай "prematurely closed". Тишина указывает обратно на проблему соединения.
- Проверьте адрес, порт и схему вышестоящего сервера в конфигурации прокси, особенно после миграции или пересборки контейнера.
- Увеличьте буферы заголовков прокси, если лог говорит, что заголовок был слишком большим, и отдельно выясните, почему заголовок разросся.
- Сделайте так, чтобы деплои перекрывались. Запустите новый процесс, дождитесь, пока он пройдет проверку здоровья, затем слейте трафик со старого и остановите его. Скользящие обновления с проверкой здоровья полностью убирают окно перезапуска, вызывающее 502 во время деплоя.
Как поймать 502, длящийся двадцать секунд
502 во время деплоя и в цикле падений короткие. Бэкенд перезапускается, отдает ошибки двадцать секунд и восстанавливается, так что к моменту, когда кто-то проверяет, сайт уже в порядке, и смотреть уже не на что. Плановая HTTP-проверка, работающая непрерывно, фиксирует эти окна с метками времени, что превращает "утром было что-то странное недолго" в паттерн, который можно сопоставить с деплоями и перезапусками. 502 также может приходить от граничного узла CDN, а не от вашего источника, поэтому проверка из нескольких регионов отличает глобальный сбой бэкенда от проблемы на границе, затрагивающей часть вашего трафика, а для этого и нужен распределенный мониторинг доступности.