Что такое reverse proxy в Nginx и зачем он нужен
Reverse proxy — сервер, который принимает запросы от клиентов и передаёт их на один или несколько бэкендов: приложение на Node.js, Python, Java или другой инстанс Nginx. Клиент обращается только к прокси и не видит внутреннюю структуру сервиса. Nginx умеет работать как reverse proxy из коробки — для этого достаточно директивы proxy_pass внутри блока location.
Reverse proxy на Nginx решает несколько задач сразу: терминирует TLS перед приложением, отдаёт статику напрямую в обход медленного бэкенда, скрывает внутренние порты и IP-адреса, добавляет заголовки безопасности. На VDS ZevsHost.net такую схему часто ставят перед Node.js или Python-приложением: Nginx слушает порт 80 и 443, а сам сервис работает на localhost и наружу не смотрит.
- Балансировка нагрузки между несколькими копиями приложения.
- Единый SSL-сертификат на весь набор внутренних сервисов.
- Кэширование ответов бэкенда без изменения кода приложения.
Настройка proxy_pass: базовый пример
Минимальный конфиг — блок server с одним location, который пересылает все запросы на локальное приложение по HTTP.
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
}
}
Если location задан с завершающим слэшем, а в proxy_pass указан путь, Nginx заменяет совпавшую часть URI на этот путь. Без пути в proxy_pass исходный URI передаётся бэкенду как есть — это самый предсказуемый вариант, особенно если приложение само разбирает маршруты. Подробнее про правила совпадения путей — в статье про приоритет location.
Передача заголовков клиента на бэкенд
По умолчанию Nginx заменяет заголовок Host на адрес бэкенда и не сообщает приложению реальный IP посетителя. Если это не поправить, в логах приложения будет виден только IP самого Nginx, а ссылки в письмах и редиректах могут указывать на localhost вместо настоящего домена.
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
Приложение на бэкенде должно доверять этим заголовкам только если запрос пришёл именно от локального Nginx, иначе клиент сможет подделать X-Forwarded-For напрямую.
Таймауты и буферы: за что отвечает каждый параметр
Если бэкенд отвечает медленно или отдаёт большой ответ, стандартные таймауты и буферы Nginx могут оборвать соединение раньше времени. Значения ниже — рабочая точка отсчёта для обычного веб-приложения, не для стриминга.
| Параметр | Назначение | Типичное значение |
|---|---|---|
| proxy_connect_timeout | ожидание установки TCP-соединения с бэкендом | 5s |
| proxy_send_timeout | время между записями данных на бэкенд | 60s |
| proxy_read_timeout | время между чтениями ответа от бэкенда | 60s |
| proxy_buffer_size | буфер для первой части ответа (заголовки) | 4k |
| proxy_buffers | количество и размер буферов для тела ответа | 8 4k |
Слишком короткий proxy_read_timeout — частая причина 504 Gateway Timeout на тяжёлых запросах вроде экспорта отчёта или загрузки файла. Слишком маленькие буферы заставляют Nginx писать временные файлы на диск, что заметно на VDS с медленным диском.
Reverse proxy к нескольким серверам через upstream
Если приложение работает в нескольких копиях, вместо одного адреса в proxy_pass используют блок upstream с списком серверов.
upstream backend {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
server 127.0.0.1:3002 backup;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://backend;
}
}
Nginx по умолчанию распределяет запросы по кругу (round robin) и пропускает сервер, помеченный backup, пока остальные живы. Про алгоритмы распределения нагрузки и проверку здоровья бэкендов — в отдельной статье про балансировщик Nginx. Если перед reverse proxy нужен ещё и HTTPS, сертификат настраивается на внешнем сервере — см. статью про SSL/TLS в Nginx.
Чек-лист: проверка reverse proxy перед продакшеном
- Заголовки Host, X-Real-IP и X-Forwarded-For переданы бэкенду и видны в его логах.
- Команда
nginx -tпроходит без ошибок после каждой правки конфига. - Таймауты подобраны под реальное время ответа приложения, а не оставлены по умолчанию.
- При нескольких бэкендах в upstream настроен хотя бы один запасной сервер.
- Ответ проверен командой
curl -I http://app.example.com/— заголовки и код статуса совпадают с ожидаемыми.