Выберите продукт

Nginx reverse proxy timeouts в Linux: proxy_read_timeout, upstream timeout, long polling и WebSocket

Таймауты в reverse proxy часто приводят к 504/499 и ошибкам «upstream timed out», даже когда бэкенд жив. Разберём proxy_read_timeout/proxy_connect_timeout/proxy_send_timeout/send_timeout, как по логам понять этап сбоя и как настроить long polling, SSE и WebSocket без сюрпризов.
Nginx reverse proxy timeouts в Linux: proxy_read_timeout, upstream timeout, long polling и WebSocket

Таймауты в reverse proxy — один из самых «коварных» классов проблем: пользователь видит 504 Gateway Timeout, фронтенд ругается на сетевые ошибки, а бэкенд при этом может работать «нормально». Особенно часто это всплывает на длинных запросах, long polling, SSE и WebSocket, а также на API, которые иногда отвечают быстро, а иногда — минутами.

Ниже — практичный разбор того, какие именно таймауты в Nginx участвуют в проксировании, как читать ошибки вида upstream timed out, и как настроить proxy_read_timeout, proxy_connect_timeout, proxy_send_timeout и send_timeout так, чтобы не залечить симптомы и не «сломать» ресурсами сервер.

Как Nginx «видит» upstream и где появляются timeouts

В режиме reverse proxy (через proxy_pass) Nginx находится между клиентом и upstream (приложение, API, второй Nginx/Apache, контейнер и т.д.). У каждой стороны свои ожидания по времени:

  • клиент ждёт ответ и может закрыть соединение сам (получим 499 в access log);
  • Nginx ждёт, что сможет подключиться к upstream, отправить запрос, а затем получать данные;
  • upstream может иметь собственные таймауты (в приложении, в Gunicorn/uWSGI/Node/Java, в балансировщике, в базе данных).

Важно: «upstream timeout» в понимании Nginx — это не один параметр, а группа таймаутов на разных стадиях. Неправильная диагностика приводит к типичному анти-паттерну: поставить proxy_read_timeout 3600 «на всякий случай», получить зависшие соединения и рост потребления памяти, а первопричина останется.

Быстрый словарь: какие timeouts за что отвечают

Чтобы разговаривать предметно, разделим процесс на этапы.

1) Подключение к upstream: proxy_connect_timeout

proxy_connect_timeout — сколько Nginx ждёт установления TCP-соединения с upstream (и если upstream по HTTPS, сюда же обычно попадает время, нужное на TLS-рукопожатие до перехода к чтению ответа).

Типичные симптомы:

  • всплески 502/504 при проблемах сети, DNS, перегруженном upstream, заполненной очереди accept;
  • в error log встречается upstream timed out (110: Connection timed out) while connecting to upstream;
  • при работе через Unix-socket чаще будет 502/503 при недоступности сокета, но при «подвисаниях» на уровне ОС тоже возможны таймауты.

2) Отправка запроса в upstream: proxy_send_timeout

proxy_send_timeout — таймаут на передачу запроса upstream’у. Он срабатывает, если Nginx не может отправлять данные (например, большой POST) из‑за того, что upstream перестал принимать (забит буфер, сеть деградировала).

В реальной жизни этот таймаут встречается реже, чем proxy_read_timeout, но он важен для API с большими payload и для загрузок через прокси.

3) Чтение ответа от upstream: proxy_read_timeout (главный герой)

proxy_read_timeout — сколько Nginx ждёт следующий байт ответа от upstream после того, как запрос уже ушёл. Таймаут измеряет «тишину» между чтениями, а не общий runtime запроса.

Отсюда два практических вывода:

  • если upstream периодически «подаёт признаки жизни» (например, стримит куски), то соединение может жить очень долго даже при умеренном proxy_read_timeout;
  • если upstream молчит 61 секунду — таймаут сработает при proxy_read_timeout 60s, даже если в целом запрос «нормально» завершается за 2 минуты.

Классика в error log:

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

Или вариант «во время чтения тела»:

upstream timed out (110: Connection timed out) while reading upstream

4) Отправка ответа клиенту: send_timeout

send_timeout — таймаут на отправку ответа клиенту. Он срабатывает, когда клиент читает слишком медленно или канал до клиента проблемный, и Nginx не может «вытолкнуть» данные из своих буферов в сокет клиента.

Это про связь Nginx → клиент, а не upstream. Полезно помнить при скачиваниях больших файлов, медленных мобильных сетях и при атаках «медленного чтения».

Схема этапов проксирования в Nginx: connect, send, read и отправка клиенту

Если вы поднимаете прокси на отдельном сервере, следите, чтобы по лимитам и ресурсам узел не стал «узким горлышком». Для таких задач обычно удобнее VDS, где можно прозрачно настроить лимиты файловых дескрипторов, keepalive и мониторинг.

Почему возникают reverse proxy timeouts на практике

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

Сценарий 1: долгие запросы (отчёты, экспорт, PDF, бэкапы)

Upstream честно работает 2–5 минут и молчит до готовности результата. Если proxy_read_timeout 60s, Nginx оборвёт запрос и вернёт 504. При этом бэкенд может продолжить работу, тратить CPU/DB и завершиться «в никуда».

Часто правильнее не увеличивать таймаут бесконечно, а изменить архитектуру: переводить долгие задачи в очередь (background job), а пользователю возвращать 202 + polling статуса. Но если менять нельзя — увеличиваем proxy_read_timeout точечно для конкретного location.

Сценарий 2: long polling

Long polling — когда клиент держит запрос открытым, пока сервер не получит событие или не истечёт таймер. Здесь конфликт «по умолчанию»: Nginx ждёт данные, upstream тоже ждёт событие, а данные не идут десятки секунд.

Чтобы long polling работал стабильно, обычно нужно:

  • увеличить proxy_read_timeout хотя бы до времени ожидания события на бэкенде плюс небольшой запас;
  • контролировать количество одновременных соединений (иначе вы сами создадите себе DoS «легальными» клиентами);
  • понимать, что 504 при long polling часто означает именно «не дождались данных», а не падение сервиса.

Сценарий 3: WebSocket

WebSocket — долгоживущее соединение, где трафик может быть редким. Если соединение простаивает, Nginx может разорвать его из‑за proxy_read_timeout (в зависимости от конфигурации и наличия ping/pong на уровне приложения).

Для WebSocket важно не только время ожидания, но и корректные заголовки Upgrade. В контексте таймаутов ключевое — обеспечить либо достаточно большой proxy_read_timeout, либо регулярные ping от клиента/сервера.

Сценарий 4: upstream перегружен, а таймауты маскируют проблему

Если база данных «задумалась» или в приложении очередь запросов, upstream начинает отвечать медленнее, Nginx получает 504, а клиенты начинают ретраить. Ретраи увеличивают нагрузку, и вы ловите лавину.

Главный принцип: таймауты лечат симптом, но не увеличивают пропускную способность. Если проблема в производительности upstream, повышение таймаутов может ухудшить ситуацию, удерживая больше активных соединений.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Диагностика: как понять, какой именно таймаут сработал

1) Смотрим error log Nginx

В error log почти всегда есть подсказка «на каком шаге» произошёл timeout:

  • while connecting to upstream — упираемся в proxy_connect_timeout или сетевую доступность;
  • while sending request to upstream — чаще про proxy_send_timeout или проблемы при отправке тела запроса;
  • while reading response header from upstream — upstream долго не отдаёт заголовки (приложение «молчит» до конца);
  • while reading upstream — заголовки пришли, но дальше тишина по телу ответа.

2) Добавляем метрики времени в access log

Чтобы не гадать, полезно логировать $request_time, $upstream_response_time, $upstream_connect_time, $upstream_header_time и статус $upstream_status. Пример формата (идея для вашего log_format):

log_format main_ext '$remote_addr - $host [$time_local] "$request" $status '
'rt=$request_time urt=$upstream_response_time uct=$upstream_connect_time '
'uht=$upstream_header_time us=$upstream_status '
'ua="$http_user_agent"';

Как читать:

  • если uct большой — проблемы подключения к upstream (сеть, лимиты, backlog);
  • если uht большой — upstream долго думает до первых байт (часто генерация отчёта);
  • если urt упирается «в потолок» — с высокой вероятностью сработал proxy_read_timeout;
  • если rt заметно больше urt — возможен медленный клиент (и влияние send_timeout), либо задержки на стороне Nginx→клиент.

Дополнительно полезно сверить общие принципы буферизации и отдачи, если у вас много крупных ответов или Range-запросы. См. разбор про Range-запросы и кеширование в Nginx/Apache.

3) Быстрая проверка со стороны ОС

Если таймауты массовые и внезапные, проверьте базовые вещи:

  • доступность upstream: слушает ли порт/сокет, нет ли ошибок DNS;
  • лимиты соединений: worker_connections, worker_rlimit_nofile, системные лимиты на открытые файлы;
  • перегруз CPU/IO: если upstream на том же сервере, то «таймаут Nginx» может быть следствием того, что приложению не хватает CPU или оно стоит в IO wait.

Практические настройки Nginx: базовый шаблон для reverse proxy

Ниже — минимальный пример, где таймауты выставлены осознанно. Значения условные: подбирайте под ваш SLA и поведение приложения.

location /api/ {
    proxy_pass http://backend;

    proxy_connect_timeout 5s;
    proxy_send_timeout 30s;
    proxy_read_timeout 60s;

    send_timeout 30s;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Идея: подключаемся быстро (5s), на отправку запроса даём разумный запас (30s), на чтение ответа — 60s, а медленным клиентам не позволяем держать соединение бесконечно (30s).

Рецепты под реальные кейсы

Долгий запрос (например, генерация отчёта до 5 минут)

Если upstream молчит до готовности результата — увеличиваем именно proxy_read_timeout в конкретном location. Не делайте это глобально на весь сайт.

location /reports/export {
    proxy_pass http://backend;

    proxy_connect_timeout 5s;
    proxy_send_timeout 60s;
    proxy_read_timeout 330s;

    send_timeout 60s;
}

Почему 330s, а не 300s: небольшой запас на сетевые колебания и очередь в приложении.

Long polling (ожидание события 30–90 секунд)

Здесь proxy_read_timeout должен быть больше максимального времени ожидания на бэкенде. Иначе Nginx будет обрывать соединение раньше, чем сервер вернёт «пустой ответ по таймеру».

location /events/poll {
    proxy_pass http://backend;

    proxy_connect_timeout 3s;
    proxy_send_timeout 10s;
    proxy_read_timeout 120s;

    send_timeout 30s;
}

Если long polling массовый, контролируйте ресурсы: каждое соединение занимает файловый дескриптор и память, а при высокой конкуренции вы упрётесь в лимиты раньше, чем в CPU.

WebSocket (долгие соединения)

Для WebSocket обычно выставляют большой proxy_read_timeout, чтобы соединение не рвалось при простое, и добавляют заголовки Upgrade. Если приложение поддерживает ping/pong — это тоже помогает.

location /ws/ {
    proxy_pass http://backend;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    proxy_connect_timeout 5s;
    proxy_send_timeout 60s;
    proxy_read_timeout 1h;

    send_timeout 60s;
}

Слишком большой таймаут — не «бесплатный»: если клиент пропал без FIN/RST (мобильная сеть, NAT), соединение может висеть до тех пор, пока не сработают TCP keepalive/таймауты ОС или прокси-таймауты.

Пример настройки Nginx для WebSocket с Upgrade и увеличенным proxy_read_timeout

Типовые ошибки и как их избежать

Ошибка 1: увеличили proxy_read_timeout, но 504 остался

Проверьте, что таймаут не на другом уровне цепочки:

  • CDN/балансировщик перед Nginx (у них часто 60–120 секунд ожидания);
  • таймауты приложения или сервера приложений;
  • таймауты клиента (браузер, мобильное приложение);
  • если запрос проходит через несколько прокси — таймаут может срабатывать раньше на «внешнем» слое.

Если вы включаете HSTS и одновременно делаете миграцию домена/сертификата, учитывайте, что ошибки на TLS-уровне могут выглядеть как «нестабильные таймауты» со стороны клиента. В таких случаях помогает чеклист миграции: переезд домена, 301, HSTS и SSL без сюрпризов.

Ошибка 2: путают send_timeout и proxy_send_timeout

send_timeout — Nginx отправляет клиенту. proxy_send_timeout — Nginx отправляет upstream. Если вы лечите медленного клиента, изменяя proxy_send_timeout, результата не будет.

Ошибка 3: «Сделаем всем по 1 часу»

Большие таймауты для всех endpoints увеличивают:

  • количество одновременно занятых соединений и давление на файловые дескрипторы;
  • расход памяти на буферы;
  • вероятность лавинообразных ретраев при деградации upstream.

Правильный подход — разные таймауты для разных маршрутов: обычные API, долгие операции, long polling/WebSocket, админка, отчёты.

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Мини-чеклист настройки таймаутов без боли

  1. Определите профиль: какие запросы быстрые, какие долгие, где long polling/WebSocket/SSE.

  2. Снимите факты: добавьте в лог $upstream_connect_time, $upstream_header_time, $upstream_response_time, $request_time.

  3. Настройте таймауты точечно по location, а не глобально.

  4. Проверьте цепочку: если перед Nginx есть ещё прокси/балансировщик — сверяйте их таймауты, иначе «узкое место» останется там.

  5. Для WebSocket/long polling продумайте keepalive/ping и лимиты одновременных соединений.

  6. Если таймауты растут из-за нагрузки — сначала масштабируйте/оптимизируйте upstream, а не растягивайте ожидание.

Заключение

Reverse proxy timeouts — это не один переключатель, а набор ограничений на разных этапах: подключение (proxy_connect_timeout), отправка запроса (proxy_send_timeout), ожидание ответа (proxy_read_timeout) и отправка клиенту (send_timeout). Большинство ошибок диагностики происходят из-за того, что администратор видит только 504 и поднимает один параметр «наугад».

Если вы начнёте с логирования upstream-таймингов и разнесёте таймауты по маршрутам (обычные API, долгие операции, long polling, WebSocket), то получите и стабильность для пользователей, и предсказуемость для эксплуатации.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: конфликт systemd-resolved DNSStubListener на 127.0.0.53 с dnsmasq, Unbound и BIND OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: конфликт systemd-resolved DNSStubListener на 127.0.0.53 с dnsmasq, Unbound и BIND

Если локальный DNS в Debian или Ubuntu не стартует с ошибкой address already in use, причина часто в systemd-resolved и DNSStubLis ...
Debian/Ubuntu: как исправить NFS mount.nfs: access denied by server while mounting OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить NFS mount.nfs: access denied by server while mounting

Ошибка mount.nfs: access denied by server while mounting в Debian и Ubuntu обычно указывает на проблему на стороне NFS-сервера: не ...
Debian/Ubuntu: как устранить конфликт systemd-resolved DNSStubListener с BIND9, dnsmasq и AdGuard Home OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как устранить конфликт systemd-resolved DNSStubListener с BIND9, dnsmasq и AdGuard Home

Если в Debian или Ubuntu DNS-сервер не стартует из-за ошибки port 53 busy, часто причина в systemd-resolved с локальным слушателем ...