Таймауты в 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. Полезно помнить при скачиваниях больших файлов, медленных мобильных сетях и при атаках «медленного чтения».

Если вы поднимаете прокси на отдельном сервере, следите, чтобы по лимитам и ресурсам узел не стал «узким горлышком». Для таких задач обычно удобнее 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, повышение таймаутов может ухудшить ситуацию, удерживая больше активных соединений.
Диагностика: как понять, какой именно таймаут сработал
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/таймауты ОС или прокси-таймауты.

Типовые ошибки и как их избежать
Ошибка 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, админка, отчёты.
Мини-чеклист настройки таймаутов без боли
Определите профиль: какие запросы быстрые, какие долгие, где long polling/WebSocket/SSE.
Снимите факты: добавьте в лог
$upstream_connect_time,$upstream_header_time,$upstream_response_time,$request_time.Настройте таймауты точечно по
location, а не глобально.Проверьте цепочку: если перед Nginx есть ещё прокси/балансировщик — сверяйте их таймауты, иначе «узкое место» останется там.
Для WebSocket/long polling продумайте keepalive/ping и лимиты одновременных соединений.
Если таймауты растут из-за нагрузки — сначала масштабируйте/оптимизируйте upstream, а не растягивайте ожидание.
Заключение
Reverse proxy timeouts — это не один переключатель, а набор ограничений на разных этапах: подключение (proxy_connect_timeout), отправка запроса (proxy_send_timeout), ожидание ответа (proxy_read_timeout) и отправка клиенту (send_timeout). Большинство ошибок диагностики происходят из-за того, что администратор видит только 504 и поднимает один параметр «наугад».
Если вы начнёте с логирования upstream-таймингов и разнесёте таймауты по маршрутам (обычные API, долгие операции, long polling, WebSocket), то получите и стабильность для пользователей, и предсказуемость для эксплуатации.


