// Engineering Log

HTTPS и веб-сервер на практике: Часть 1 — Ошибки 502, 504, 499 и 413 в Nginx: причины и таймауты

Опубликовано 28.10.2026

// Быстрый маршрут

Эта статья относится к теме Серверы и инфраструктура.

Коды 502, 504, 499 и 413 почти никогда не отдаёт само приложение. Их возвращает Nginx, который стоит перед ним: он не смог подключиться к приложению, не дождался ответа, получил обрыв соединения или отказался принимать слишком большой запрос. Поэтому причину ищут не в коде приложения, а на стыке Nginx и приложения — в журнале ошибок Nginx и в согласовании таймаутов. Ниже — что означает каждый код, какие строки журнала ему соответствуют и что менять в настройках. Общие сведения о кодах состояния — в статье «Что такое HTTP: запрос, ответ, методы и коды состояния».

Сначала — журнал

В access.log видно только код, причина — в error.log (обычно /var/log/nginx/error.log). Строка ошибки содержит адрес приложения (upstream), запрос и системную причину:

2026/09/24 10:15:02 [error] 1234#1234: *5678 connect() failed (111: Connection refused)
while connecting to upstream, client: 192.0.2.7, server: example.ru,
request: "GET /api/orders HTTP/2.0", upstream: "http://127.0.0.1:8080/api/orders"

Чтобы видеть время ответа приложения прямо в журнале доступа, расширьте формат:

nginx
log_format upstream '$remote_addr "$request" $status '
                    'rt=$request_time uct=$upstream_connect_time '
                    'urt=$upstream_response_time us=$upstream_status ua=$upstream_addr';
access_log /var/log/nginx/access.log upstream;
  • $request_time — сколько Nginx обрабатывал запрос целиком, включая передачу клиенту;
  • $upstream_connect_time — время подключения к приложению;
  • $upstream_response_time — сколько отвечало приложение;
  • $upstream_status и $upstream_addr — что ответило приложение и какой из серверов. Если серверов несколько и Nginx пробовал следующий, значения идут через запятую: 502, 200.

502 Bad Gateway

Nginx не получил от приложения корректного ответа. Причину определяет текст в error.log.

connect() failed (111: Connection refused) — на указанном адресе и порту никто не слушает. Приложение не запущено, упало, слушает другой порт или только 127.0.0.1, когда Nginx обращается по внешнему адресу (частый случай в Docker: приложение слушает 127.0.0.1 внутри контейнера и недоступно из соседнего). Проверка:

bash
ss -ltnp | grep 8080
curl -v http://127.0.0.1:8080/

connect() to unix:/run/php/php8.3-fpm.sock failed (2: No such file or directory) — сокета нет: PHP-FPM не запущен или в Nginx указана другая версия PHP.

(13: Permission denied) while connecting to upstream — у Nginx нет прав на сокет (проверьте listen.owner и listen.group в пуле PHP-FPM) или, в CentOS, Rocky и RHEL, SELinux запрещает подключение: setsebool -P httpd_can_network_connect 1.

(11: Resource temporarily unavailable) while connecting to upstream — очередь соединений к сокету переполнена: все процессы PHP-FPM заняты. Смотрите в журнале PHP-FPM сообщение server reached pm.max_children setting и увеличивайте pm.max_children, если позволяет память, или ищите медленные запросы.

upstream prematurely closed connection while reading response header from upstream — приложение закрыло соединение, не ответив. Причины: процесс упал на этом запросе (смотрите журнал приложения, dmesg на предмет OOM killer), приложение само оборвало долгий запрос по своему таймауту, или гонка keepalive (ниже).

recv() failed (104: Connection reset by peer) — приложение сбросило соединение. Причины те же.

upstream sent too big header while reading response header from upstream — заголовки ответа не помещаются в буфер: обычно много или большие cookie, длинный Location. Увеличьте буфер:

nginx
proxy_buffer_size 16k;
proxy_buffers 8 16k;
# для PHP-FPM — fastcgi_buffer_size и fastcgi_buffers

no live upstreams while connecting to upstream — все серверы в блоке upstream помечены недоступными после ошибок (параметры max_fails и fail_timeout). Это следствие: ищите в журнале первые ошибки перед этой строкой.

Гонка keepalive: 502 раз в несколько минут

Если 502 появляются редко, без нагрузки и без ошибок в журнале приложения, почти наверняка это гонка keepalive между Nginx и приложением.

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

Пример: у Node.js server.keepAliveTimeout по умолчанию 5 секунд, а Nginx держит простаивающее соединение к приложению до 60 секунд (keepalive_timeout в блоке upstream). Через 5 секунд простоя Node.js закрывает соединение, Nginx пытается им воспользоваться — и получает 502.

Правило: таймаут простоя у того, кто ближе к приложению, должен быть больше, чем у того, кто перед ним. Либо уменьшите таймаут в Nginx, либо увеличьте в приложении:

nginx
upstream app {
    server 127.0.0.1:3000;
    keepalive 32;
    keepalive_timeout 4s;    # меньше, чем keepAliveTimeout в Node.js (5 с)
}

server {
    location / {
        proxy_pass http://app;
        proxy_http_version 1.1;
        proxy_set_header Connection "";   # без этого keepalive к приложению не работает
    }
}
javascript
// или в Node.js: больше, чем держит соединения тот, кто стоит перед приложением
server.keepAliveTimeout = 65000;
server.headersTimeout = 66000;

То же правило действует для всей цепочки: облачный балансировщик → Nginx → приложение. У AWS ALB таймаут простоя по умолчанию 60 секунд, значит, у Nginx за ним keepalive_timeout для клиентов должен быть больше 60 секунд.

504 Gateway Timeout

Nginx подключился к приложению, но не дождался ответа за отведённое время:

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

Таймауты Nginx при проксировании:

ДирективаПо умолчаниюЧто ограничивает
proxy_connect_timeout60 сустановку соединения с приложением (больше 75 с не задать)
proxy_send_timeout60 спаузу между двумя операциями записи запроса приложению
proxy_read_timeout60 спаузу между двумя операциями чтения ответа — не общее время ответа
fastcgi_read_timeout60 сто же для PHP-FPM

Что делать:

  1. Найти медленный запрос. 504 — симптом: приложение слишком долго работает. Смотрите urt= в журнале, медленные запросы к базе, внешние API без таймаутов.

  2. Увеличить таймаут только там, где долгий ответ — норма, например для выгрузки отчётов, а не глобально:

    nginx
    location /reports/ {
        proxy_pass http://app;
        proxy_read_timeout 300s;
    }
  3. Согласовать таймауты по всей цепочке. Увеличить proxy_read_timeout бесполезно, если раньше срабатывает таймаут в другом месте: max_execution_time и request_terminate_timeout в PHP, таймаут воркера в Gunicorn (--timeout, по умолчанию 30 с), таймаут CDN (у Cloudflare ответ должен начаться за 100 секунд, иначе — ошибка 524).

  4. Долгие операции — в фон. Если отчёт строится пять минут, правильнее принять задание, вернуть 202 Accepted и отдать результат по готовности, а не держать HTTP-запрос открытым.

proxy_connect_timeout срабатывает, только если приложение не отвечает на подключение вовсе (адрес недоступен, пакеты теряются) — тогда в журнале while connecting to upstream. Отказ в соединении (Connection refused) приходит мгновенно и даёт 502, а не 504.

499 Client Closed Request

Код, придуманный в Nginx: клиент закрыл соединение, не дождавшись ответа. Клиенту этот код не отправляется — только пишется в журнал.

Причины:

  • пользователь закрыл вкладку или ушёл со страницы, пока она грузилась. Единичные 499 — норма;
  • у клиента свой таймаут меньше, чем время ответа: мобильное приложение ждёт 30 секунд, API отвечает за 40. Массовые 499 с одинаковым $request_time — признак именно этого;
  • перед Nginx стоит балансировщик или CDN со своим таймаутом, и он закрывает соединение раньше;
  • мониторинг проверяет доступность с коротким таймаутом.

По умолчанию, когда клиент уходит, Nginx закрывает и соединение с приложением (proxy_ignore_client_abort off), но приложение может продолжить работу и не узнать, что результат никому не нужен. Если 499 массовые — это та же проблема, что 504: медленные ответы, только таймаут сработал у клиента.

413 Content Too Large

Тело запроса больше разрешённого. В Nginx по умолчанию — 1 МБ, поэтому загрузка фотографии или документа через сайт первой упирается именно в этот лимит:

client intended to send too large body: 5242880 bytes
nginx
server {
    client_max_body_size 50m;   # для всего сайта
    location /upload/ {
        client_max_body_size 500m;   # для загрузок — больше
    }
}

Лимит есть и дальше по цепочке, и поднимать его нужно везде:

  • PHP — upload_max_filesize и post_max_size в php.ini;
  • фреймворк приложения — например, DATA_UPLOAD_MAX_MEMORY_SIZE в Django, bodyParser в Express;
  • CDN — у Cloudflare на бесплатном и Pro-тарифах тело запроса ограничено 100 МБ.

Для больших файлов лучше загрузка частями (протокол tus) или прямая загрузка в объектное хранилище по подписанной ссылке, минуя приложение.

Другие коды от Nginx

  • 400 Request Header Or Cookie Too Large — заголовки или cookie не помещаются в буфер: large_client_header_buffers 4 16k;.
  • 503 Service Temporarily Unavailable — часто это не авария, а сработавшее ограничение частоты limit_req или limit_conn: по умолчанию они отвечают именно 503. В журнале — limiting requests, excess:. Отдавать правильный код 429 можно директивой limit_req_status 429;.
  • 500 с rewrite or internal redirection cycle — бесконечный цикл try_files или rewrite.
  • 403 с directory index of "/var/www/…/" is forbidden — запрошен каталог, в нём нет index.html/index.php, а листинг выключен. С (13: Permission denied) — у пользователя Nginx нет прав на файлы.

Ошибки Cloudflare 52x

Если сайт за Cloudflare, ошибки на стыке CDN и вашего сервера имеют свои коды — это аналоги 502 и 504, но между Cloudflare и Nginx:

КодЧто значит
520сервер вернул пустой или непонятный ответ
521сервер отказал в соединении — Nginx не запущен или порт закрыт для адресов Cloudflare
522таймаут подключения к серверу
523сервер недоступен (неверный адрес в DNS)
524соединение есть, но ответ не начался за 100 секунд
525не удалось рукопожатие TLS с сервером
526неверный сертификат на сервере в режиме Full (strict)

Порядок диагностики

  1. Найти строку в error.log по времени и адресу — текст ошибки почти всегда указывает на причину.
  2. Проверить приложение напрямую, минуя Nginx: curl -v http://127.0.0.1:8080/путь.
  3. Сравнить $request_time и $upstream_response_time: если время уходит в приложении — искать там, если нет — в сети или в Nginx.
  4. Выписать таймауты всей цепочки — CDN, балансировщик, Nginx, приложение, база — и проверить, что каждый следующий согласован с предыдущим.
  5. Для редких 502 без видимой причины — проверить keepalive между Nginx и приложением.

// Похожая задача

Если у вас похожая ситуация

Эта статья относится к одной из рабочих тем. Можно продолжить чтение по теме, перейти на главную, чтобы понять, чем я занимаюсь, или сразу открыть услуги.

Тема статьи

Серверы и инфраструктура

VPS, Linux, веб-стек, миграции, хостинг, базы данных и базовая эксплуатация.

Часто с этим приходят

  • Перенести сайт или сервис на новый сервер
  • Настроить Linux, Nginx, базу данных и бэкапы
  • Разобраться, почему всё работает нестабильно

// Следующий шаг

Если вам нужна не только статья, а помощь по этой теме, удобнее сразу перейти в услугу. Главная и подборка материалов остаются рядом.

Открыть услуги

// Reviews

Отзывы по теме

Спасибо Михаилу за отзывчивость. Созвонились, объяснил как сделать самому. Обращаюсь уже второй раз, все супер и оперативно.

Спасибо Михаилу за отзывчивость. Созвонились, объяснил как сделать самому. Обращаюсь уже второй раз, все супер и оперативно.

kireevk

kireevk

Консультация по nginx proxy manager и portainer

25.02.2025 · ★ 5/5

Освоившийся покупатель
apande

apande

Настройка nginx и opencart

07.09.2024 · ★ 5/5

Очень мощный покупатель
kireevk

kireevk

Диагностика Nginx Proxy Manager в docker контейнере и решение проблемы

15.03.2024 · ★ 5/5

Освоившийся покупатель

// Contact

Нужна помощь?

Свяжись со мной и я помогу решить проблему

Написать в Telegram

Отвечаю в течение рабочего дня (03:00–13:00 GMT)

Или оставьте заявку здесь:

Подтвердите, что вы не бот.

Написать и получить быстрый ответ