Новинка Виртуальный VDS сервер в Нидерландах от 390р
Выберите продукт

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-сервер
Виртуальные серверы с быстрым запуском и гибкой конфигурацией от 390₽ / мес
Доступные локации
Россия Нидерланды

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

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), то получите и стабильность для пользователей, и предсказуемость для эксплуатации.

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

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

Как безопасно выполнить bootstrap MariaDB Galera после полного останова

Как безопасно выполнить bootstrap MariaDB Galera после полного останова

После одновременной остановки всех узлов Galera обычного запуска MariaDB недостаточно. Сначала найдите сервер с последней транзакц ...
CoreDNS в Kubernetes: исправляем CrashLoopBackOff, SERVFAIL и DNS-петлю

CoreDNS в Kubernetes: исправляем CrashLoopBackOff, SERVFAIL и DNS-петлю

Разберём, почему CoreDNS перезапускается или отвечает SERVFAIL, как обнаружить замкнутую пересылку DNS-запросов, проверить доступн ...
Apache Kafka KRaft на VDS: отдельные controller и broker

Apache Kafka KRaft на VDS: отдельные controller и broker

Соберём новый Kafka-кластер без ZooKeeper на шести Linux VDS: три узла controller образуют отказоустойчивый metadata quorum, а три ...