Loading...

Основы · 8 мин чтения

502 Bad Gateway: что это значит и как это исправить

502 — это не вина вашего посетителя, и почти никогда не вина CDN. Это значит, что машина перед вашим сайтом запросила у вашего сервера страницу и получила то, чем не смогла воспользоваться. Это руководство написано со стороны прокси: что именно увидел edge и какая из четырёх причин сработала.

Обновлено

502 Bad Gateway: что это значит и как это исправить

Кто на самом деле говорит «bad gateway»

Код ответа генерирует не само приложение, а то, что стоит перед ним. Запрос проходит путь посетитель → edge CDN → ваш origin-сервер → (часто) сервер приложения, и любой узел, который проксирует запрос дальше, может выдать 502 про следующий за ним узел. Это важно, потому что страницу, которую вы видите, написал именно прокси: если бы ваше приложение хоть как-то ответило, пусть даже ошибкой, вы бы видели свою собственную страницу 500.

Значит, 502 — это утверждение о разговоре, который не состоялся, и полезный вопрос всегда один и тот же: какие две машины разговаривали и что пошло не так между ними?

502 против 504: различие, которое все пропускают

В блог-постах эти два кода часто используют как взаимозаменяемые, а делать этого не стоит.

504 Gateway Timeout означает, что прокси успешно подключился, а затем ждал. Ваш origin принял запрос и не успел ответить в пределах таймаута. Обычные причины — медленный запрос к базе данных, вызов внешнего API без собственного таймаута или переполненный пул процессов, который ставит запросы в очередь.

502 Bad Gateway означает, что ждать было нечего — пригодного ответа просто не появилось. Либо в соединении отказали, либо его приняли и тут же оборвали, либо вернувшиеся байты не были валидным HTTP-ответом.

Если вы видите 504 — смотрите, сколько времени занимает работа вашего приложения. Если видите 502 — смотрите, отвечает ли приложение вообще.

Причина 1 — origin отказал в соединении

Прокси открыл TCP-соединение к вашему origin и сразу получил отказ либо маршрута не нашлось вовсе. Либо на этом порту никто не слушал, либо файрвол отбросил пакет.

На практике это вызывают: веб-сервер или контейнер остановлен; он слушает 127.0.0.1 вместо публичного интерфейса; порт в настройках origin не совпадает с портом, на котором реально работает сервис; файрвол хоста или security group блокирует IP-адреса CDN.

Как проверить. Извне своей сети обратитесь к origin напрямую, отправив заголовок Host, который использует ваш сайт, — иначе origin, обслуживающий несколько сайтов, ответит не тому или откажет:

curl -sI -H "Host: example.com" http://ORIGIN_IP/

Если этот curl падает точно так же — CDN говорит правду, и чинить нужно на origin. Если этот curl проходит успешно, а edge видит отказ, разница почти всегда в правиле файрвола, которое пускает вас, но не edge.

Причина 2 — origin разорвал соединение раньше времени

Соединение приняли, но оно оборвалось раньше, чем вернулся полный ответ. Это самый частый 502 на стеках PHP и Node под нагрузкой.

Его вызывают: пул PHP-FPM, где заняты все воркеры, так что новые соединения принимает backlog ядра и затем сбрасывает; воркер, упёршийся в лимит памяти и убитый посреди ответа; процесс приложения, упавший именно на этом запросе; несовпадение по keepalive, когда origin закрывает простаивающие соединения раньше, чем прокси рассчитывает их переиспользовать.

Как проверить. Посмотрите собственный лог ошибок origin в момент 502 — это тот редкий случай, когда origin может рассказать всё прямо. Строка Premature end of script headers, segfault или предупреждение PHP-FPM server reached pm.max_children прямо называют причину. Если 502 группируются на пиках трафика, а не появляются случайно, — это исчерпание пула, а не баг.

Причина 3 — провален TLS-хендшейк до origin

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

Это вызывают: сертификат origin истёк, и никто не заметил, потому что публичный сертификат обновляется автоматически; origin обслуживает несколько имён, и ему нужен SNI, чтобы выбрать нужное; origin принимает только те версии TLS или наборы шифров, которых прокси не предлагает; сертификат покрывает www.example.com, а прокси подключается, запрашивая example.com.

Как проверить.

openssl s_client -connect ORIGIN_IP:443 -servername example.com </dev/null | head -20

Посмотрите на цепочку и даты. На cdn.com.tr edge отправляет SNI на origin, поэтому сертификат, действительный для настроенного вами хоста, согласуется успешно; сертификат, действительный только для vhost по умолчанию, — нет.

Причина 4 — ответ не был валидным HTTP

Реже встречается, но найти приятно. Origin ответил, но то, что пришло, не удалось разобрать: строка заголовка длиннее буфера прокси, случайная строка вывода, напечатанная перед заголовками (предупреждение PHP, метка порядка байтов в подключаемом файле), ответ с Content-Length, не совпадающим с телом, или текстовый дамп аварийного завершения, отданный на порту 443.

Как проверить. Обратитесь к origin напрямую и посмотрите на сырые байты, а не на отрендеренную страницу:

curl -sv -H "Host: example.com" http://ORIGIN_IP/ -o /dev/null

Если первая строка ответа — не HTTP/1.1 ..., вы нашли причину. Исправление — в вашем приложении или его буферизации вывода, и прокси был прав, что отказал.

Что делать, когда впереди CDN

CDN меняет диагностику двумя полезными способами.

Закэшированные страницы продолжают отдаваться. Посетитель, запрашивающий то, что уже есть в кэше edge, получает это, даже пока origin лежит, так что частичный 502 — часть страниц сломана, часть работает — обычно означает, что origin жив, но падает на некэшируемых путях, а это, как правило, динамические страницы.

У вас появляется вторая точка наблюдения. Edge постоянно видит ваш origin снаружи. Если edge сообщает 502, а ваш собственный браузер до origin достучался, разница между этими двумя запросами и есть баг: файрвол, который пускает ваш IP, DNS-запись, которая для вас указывает в другое место, или сертификат, который совпадает только с тем именем, которое случайно используете вы.

На cdn.com.tr правила доставки позволяют держать более долгий TTL кэша на путях, которые это допускают, — именно это превращает инцидент на origin в деградацию сайта, а не в его полную недоступность. Это стоит настроить заранее, а не в момент, когда это уже понадобилось.

502, который вообще не про ваш origin

Один случай стоит назвать отдельно, потому что на него уходят часы. Если ваш DNS указывает на edge CDN, но хост ещё не настроен на этом edge, вы получите не 502, а 503 со страницей о том, что для этого домена не настроен ни один сервис. Так edge сообщает, что вообще не знает, к какому origin обращаться.

Люди видят страницу ошибки сразу после смены DNS, решают, что origin сломан, и начинают перезапускать сервисы, которые вообще ни при чём. Сначала проверьте код ответа: 502 означает, что edge пытался обратиться к вашему origin и получил сбой; такой 503 означает, что edge вообще не было к какому origin обращаться.

Частые вопросы

502 — это моя вина или вина CDN?

Обычно ни то, ни другое — это дело origin. CDN сообщает о сбое, который реально произошёл, а не выдумывает его. Исключение, которое стоит проверить, — связность: если файрвол origin блокирует IP-адреса edge, для вас origin здоров, а для CDN недоступен, и решение — правило разрешения, а не что-то в приложении.

Почему 502 появляется только иногда?

Периодические 502 почти всегда означают нехватку ёмкости, а не проблему конфигурации. Переполненный на пиках пул процессов, воркер, который перезапускается, или origin, закрывающий keepalive-соединения раньше, чем ожидает прокси, — всё это даёт ошибки, которые то появляются, то исчезают, пока простой тест с вашего ноутбука проходит каждый раз.

Помогает ли обновление страницы?

Оно о чём-то говорит. Если обновление помогает, сбой периодический, и дело в ёмкости или конкретном воркере. Если каждое обновление падает одинаково, дело в конфигурации — отказ в соединении, неверный порт, истёкший сертификат origin, — и обновление тут ничего не изменит.

Как отличить 502 от 504, не глядя на код ответа?

По тому, сколько вы ждали. 504 заставляет дождаться таймаута — обычно это десятки секунд, потому что прокси действительно ждёт ответа. 502 обычно приходит быстро, потому что отказ в соединении или его обрыв случаются мгновенно.

Можно ли показать посетителям что-то лучше страницы ошибки по умолчанию?

Да, и стоит это сделать. CDN может отдать устаревшую закэшированную версию или брендированную страницу ошибки вместо стандартной страницы прокси — тогда авария превращается в чуть менее удобный опыт, а не в полную поломку. Настройте это заранее, потому что во время самого инцидента вам будет не до этого.