upstream timed out (110: Connection timed out) в error.log nginx — не диагноз «маленький таймаут». Слова после сообщения показывают фазу: connecting, sending или reading. Сначала сопоставьте время, upstream-адрес и request ID с логом приложения; затем меняйте конкретный лимит, если он действительно слишком мал для нормальной операции.

nginx выступает посредником между клиентом и upstream. Код 110 соответствует системному таймауту, но без фазы нельзя выбрать директиву. Ошибка чтения от медленного приложения отличается от невозможности установить TCP-соединение. Для типичных HTTP и FastCGI маршрутов используются разные наборы директив из proxy module и FastCGI module. Если внешний слой ещё один CDN, клиентский код может отличаться от того, что записал nginx; см. карту кодов 5xx.

Определите фазу по формулировке журнала
| Фраза error.log | Участок | Директива HTTP proxy | Первая проверка |
|---|---|---|---|
while connecting to upstream | Открытие соединения | proxy_connect_timeout | Адрес, порт, сеть, число доступных соединений |
while sending request to upstream | Отправка запроса | proxy_send_timeout | Читает ли upstream тело и не заблокирован ли он |
while reading response header from upstream | Ожидание заголовка | proxy_read_timeout | Очередь и время работы приложения |
while reading upstream | Чтение тела | proxy_read_timeout | Паузы между порциями ответа |
Для PHP-FPM замените proxy_* на соответствующие fastcgi_* и проверьте очередь FPM. Оба read timeout считают паузу между операциями чтения, а не общий лимит на всю передачу. Долгий streaming-ответ может продолжаться дольше лимита, если данные приходят регулярно; молчание между порциями приведёт к таймауту.
Сопоставьте журнал с временем запроса
log_format upstream '$time_iso8601 request_id=$request_id $host "$request" '
'status=$status upstream=$upstream_addr '
'upstream_status=$upstream_status '
'connect=$upstream_connect_time header=$upstream_header_time '
'response=$upstream_response_time total=$request_time';
access_log /var/log/nginx/access_upstream.log upstream;
Включайте формат после nginx -t; не логируйте токены из URL без политики редактирования. $upstream_connect_time измеряет установление соединения, $upstream_header_time — время до заголовка, $upstream_response_time — до завершения ответа upstream. При ретраях могут появляться последовательности значений: сопоставляйте каждый адрес и статус, а не берите одну цифру. Формат полей документирован в модуле логирования.
Снаружи снимите разбиение времени curl и сопоставьте тот же запрос по ID внутри. Если в приложении запрос выполняется быстро, а nginx ждёт подключение, ищите сетевой или пуловый лимит. Если приложение само тратит 90 секунд на БД, увеличение proxy_read_timeout до 120 секунд лишь продлит ожидание: проверьте план запроса и загрузку зависимостей. Если upstream закрывает простаивающее соединение, изучите несовпадение keep-alive.
Меняйте лимит контролируемо
Сначала зафиксируйте текущий конфиг через nginx -T и реальные квантили времени ответа. Затем меняйте только директиву участка, на котором происходит задержка, и сверяйте лимиты соседних прокси. Учитывайте таймаут клиента: бессмысленно ждать upstream 120 секунд, если внешний CDN оборвёт запрос через 30. После reload проверьте частоту ошибок, время ответа и число одновременно занятых соединений. При росте хвоста откатите изменение и устраните источник задержки.
Как сделан материал
Сопоставление фаз и директив основано на официальной документации nginx. Примеры формата журнала — шаблоны для диагностики; статья не выдаёт их за реальный инцидент enterno.io. В SerpAPI изучены запросы Google US и Яндекса; Wordstat региона 225 показал 11 для точной фразы и 12 для более широкой. Спрос не влияет на технический диагноз.
Частые вопросы
Почему после proxy_read_timeout стало 504, а не 502?
Код формирует конкретный шлюз. Смотрите его access/error.log и следующий внешний слой.
Можно ли поставить 300 секунд сразу?
Технически можно, но это может скрыть задержку и занять соединения. Сначала измерьте нормальное время операции и пределы соседних узлов.
Почему таймаут случился при скачивании?
Read timeout ограничивает паузу между чтениями, поэтому проблема может возникнуть после заголовка при долгом молчании upstream.
Как отличить сеть от медленного приложения?
Сопоставьте фазу error.log, connect/header/response times и журнал приложения по request ID.