Заголовки, таймауты и буферы проксирования
Базовый proxy_pass работает, но прод требует деталей: правильные заголовки, разумные таймауты и буферы, иначе один медленный бэкенд утянет всё.
«Таймаут — это не пессимизм, это страховка. Без него зависший бэкенд держит соединения вечно.»
В прошлом уроке мы подняли прокси. Теперь сделаем его надёжным. Три темы: заголовки (что доносим до бэкенда), таймауты (когда сдаёмся) и буферы (как не задушить бэкенд медленным клиентом).
Заголовки проксирования
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;
proxy_set_header X-Forwarded-Host $host;
Переменная $proxy_add_x_forwarded_for аккуратно дописывает IP клиента в конец уже существующей цепочки X-Forwarded-For (если запрос прошёл через несколько прокси). $scheme сообщает бэкенду, был ли запрос по http или https — критично, когда Nginx терминирует TLS, а бэкенд работает по http.
Таймауты
proxy_connect_timeout 5s; # сколько ждать установки соединения с бэкендом
proxy_send_timeout 60s; # пауза при отправке запроса бэкенду
proxy_read_timeout 60s; # пауза при чтении ответа бэкенда
Без таймаутов зависший бэкенд держит соединение бесконечно, и они копятся, пока Nginx не упрётся в лимиты. proxy_connect_timeout ставь небольшим (3–5s): если бэкенд не отвечает на коннект быстро — он, скорее всего, мёртв.
Буферизация
proxy_buffering on;
proxy_buffers 8 16k; # 8 буферов по 16 КБ на ответ
proxy_buffer_size 16k; # буфер под заголовки ответа
Обработка ошибок бэкенда
location / {
proxy_pass http://127.0.0.1:8000;
proxy_next_upstream error timeout http_502 http_503;
error_page 502 503 504 /maintenance.html;
}
location = /maintenance.html {
root /var/www/errors;
internal;
}
Как работает под капотом
При proxy_buffering on Nginx читает ответ бэкенда в свои буферы и, как только бэкенд закончил, освобождает его — даже если клиент ещё качает ответ по медленному мобильному интернету. Так один воркер приложения обслуживает больше запросов в секунду. Если ответ не влезает в память, Nginx сбрасывает остаток во временный файл на диск. Для стриминга (Server-Sent Events, длинные потоки) буферизацию, наоборот, отключают: proxy_buffering off;.
Частые ошибки
- Дефолтный
proxy_read_timeout 60sдля долгих операций. Тяжёлый отчёт на 90 секунд оборвётся на 60-й. Подними таймаут именно для этого location. - Буферизация при стриминге. SSE/стрим «залипают», потому что Nginx ждёт полного ответа. Отключи
proxy_bufferingдля таких маршрутов. - Грязный X-Forwarded-For. Если доверять заголовку от клиента вслепую, его можно подделать. За доверенными прокси используй
$proxy_add_x_forwarded_forи настройreal_ip.
Best practices
- Короткий
proxy_connect_timeout(3–5s), разумные send/read под характер маршрута. - Красивая
error_pageдля 502/503/504 — пользователь увидит «идут работы», а не голую ошибку Nginx. - Для стриминговых эндпоинтов —
proxy_buffering offточечно.
Восстановление реального IP клиента
Передать заголовки мало — бэкенд должен ещё и правильно их прочитать, а это отдельная тема. Когда Nginx проксирует запрос, для приложения источником становится сам Nginx (127.0.0.1 или адрес внутренней сети). Реальный IP клиента уезжает в X-Forwarded-For, но приложение увидит его только если настроено доверять этому заголовку. Если бэкенд логирует remote_addr «как есть», все запросы будут выглядеть пришедшими с localhost — бесполезно для аналитики, антифрода и блокировок.
У Nginx для этого есть модуль real_ip: директивы set_real_ip_from (каким прокси доверять) и real_ip_header X-Forwarded-For заставляют сам Nginx подставить настоящий IP клиента в $remote_addr — удобно, когда перед Nginx стоит ещё и CDN вроде Cloudflare. Тут же кроется и риск безопасности: X-Forwarded-For легко подделать, поэтому доверять ему можно только от известных, контролируемых прокси, а от внешнего клиента — никогда. Иначе атакующий пропишет себе любой IP и обойдёт ограничения по адресу. Правило простое: настрой доверенные диапазоны явно, и тогда цепочка X-Forwarded-For станет надёжным источником правды о том, кто на самом деле к тебе пришёл.
Итоги
Надёжный прокси = правильные заголовки (Host, X-Forwarded-*), осмысленные таймауты (быстрый connect, адекватные read/send под нагрузку), буферизация для защиты бэкенда от медленных клиентов и красивые страницы ошибок. Точечно отключай буферизацию для стриминга. Дальше — апстримы и пулы соединений, фундамент балансировки.