Nginx как reverse proxy: базовая настройка с нуля
Меня зовут Семёнов Евгений Сергеевич, директор АйТи Фреш. За 15+ лет я поставил Nginx в качестве reverse proxy, наверное, несколько сотен раз — перед 1С-Битрикс, WordPress, Nextcloud, GitLab, Mattermost, внутренними API на Node.js и Django. И каждый раз сталкиваюсь с тем, что типовая настройка в Интернете либо устарела, либо ломает половину приложений. Поэтому пишу свой рабочий конфиг, который проверен на продакшене.
Что такое reverse proxy и когда он нужен
Reverse proxy — это сервер-посредник между клиентами и вашими приложениями. Клиент видит Nginx, Nginx видит приложение. Плюсы простые и понятные:
- SSL-терминация. Сертификат живёт на одном Nginx, приложения по HTTP по внутренней сети — проще обновлять.
- Один публичный IP. На одном сервере десятки сайтов через server_name.
- Кеширование статики и API-ответов. Снимает нагрузку с бэкенда.
- Rate limiting и защита. Ограничение запросов, бан бот-ферм.
- Zero-downtime deploy. Переключение upstream без разрыва соединений.
- Единая точка логов. Все обращения в одном access_log.
У нас на практике reverse proxy стоит перед 100% веб-приложений у клиентов — других вариантов, если честно, я не вижу.
Установка Nginx под Debian/Ubuntu
В репозитории Ubuntu версия часто отстаёт. Я всегда ставлю из официального репозитория nginx.org — там stable или mainline:
apt update && apt install -y curl gnupg2 ca-certificates
curl https://nginx.org/keys/nginx_signing.key | \
gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" > /etc/apt/sources.list.d/nginx.list
apt update && apt install -y nginx
systemctl enable --now nginx
Проверяем:
nginx -v
nginx -T | head -50
Структура файлов и правильная организация
Я ни разу не правлю nginx.conf напрямую для сайтов. Только общие параметры там. Сайты — отдельные файлы в /etc/nginx/conf.d/ или sites-available/sites-enabled. Минимальный /etc/nginx/nginx.conf:
user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 16384;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
client_max_body_size 256M;
client_body_timeout 60s;
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" rt=$request_time ut=$upstream_response_time';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
include /etc/nginx/conf.d/*.conf;
}
Базовый конфиг обратного прокси
Кладу файл /etc/nginx/conf.d/app.example.ru.conf. Приложение работает на 127.0.0.1:3000 (Node.js, к примеру). Nginx слушает 80 и редиректит на 443:
upstream app_backend {
server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
keepalive 32;
}
server {
listen 80;
server_name app.example.ru;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name app.example.ru;
ssl_certificate /etc/letsencrypt/live/app.example.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.example.ru/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 1d;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
access_log /var/log/nginx/app.access.log main;
error_log /var/log/nginx/app.error.log;
location / {
proxy_pass http://app_backend;
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;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffers 16 16k;
proxy_buffer_size 32k;
}
}
Этот конфиг я использую как стартовый шаблон, дальше добавляю специфику под каждое приложение.
Сертификат через Let's Encrypt
Certbot ставится из snap или из пакета. Предпочитаю snap — актуальнее версии плагинов:
apt install -y certbot python3-certbot-nginx
certbot --nginx -d app.example.ru --redirect --agree-tos -m admin@example.ru
Автообновление сертификатов уже в cron — раз в 12 часов, проверяет срок и обновляет за 30 дней до истечения.
WebSocket и long-polling
Если приложение использует WebSocket (Mattermost, Rocket.Chat, онлайн-чаты, админки Node.js) — стандартный конфиг обрежет соединение через 60 секунд. Я всегда добавляю отдельный location или глобальную поддержку:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
location /ws/ {
proxy_pass http://app_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
Блок map пишется в http {}, а location /ws/ уже внутри server {}. На Mattermost/Rocket.Chat — это обязательная конфигурация, иначе пользователи получают «disconnected» каждую минуту.
Кеширование бэкенда
Если приложение отдаёт тяжёлые ответы, которые меняются редко — кешируем их в Nginx. Типовой пример — списки товаров, RSS-ленты, API курсов валют:
# В http {}
proxy_cache_path /var/cache/nginx/app_cache levels=1:2 keys_zone=app_cache:100m max_size=5g
inactive=7d use_temp_path=off;
# В location
location /api/catalog/ {
proxy_cache app_cache;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 5m;
proxy_cache_valid 404 30s;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_background_update on;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://app_backend;
}
Флаг X-Cache-Status в заголовке ответа показывает HIT/MISS/UPDATING — удобно отлаживать.
Реальный кейс: портал и внутренний Helpdesk в одной коробке
В августе 2025 клиент — дистрибьютор электронных компонентов, 45 рабочих мест — попросил «всё на один сервер». У них был внешний Битрикс24-портал, внутренний Helpdesk GLPI, Kanboard и система документооборота. Каждое приложение крутилось на своей виртуалке, каждая занимала 3 публичных IP. Бардак.
Собрал один сервер Dell с Xeon Platinum 8280, 128 ГБ RAM, 40G Mellanox до свича в дата-центре МТС. Поднял Nginx reverse proxy, сертификаты Let's Encrypt на 7 поддоменов. Все приложения остались на своих виртуалках внутренней сетью, но публично — один IP и один Nginx. Добавил кеш статики по /static/, WebSocket для GLPI, rate limiting на /api/. Ошибок стало меньше, администрирование — проще, SSL сертификаты один раз настроил и забыл. Внедрение заняло 4 дня, стоимость — 72 000 руб.
Мониторинг и типичные ошибки
После настройки обязательно включаю stub_status для мониторинга:
server {
listen 127.0.0.1:8080;
server_name _;
location /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
}
Prometheus nginx_exporter цепляется за эту страницу и собирает Active connections, reading/writing/waiting.
Типовые грабли:
- 502 Bad Gateway. Бэкенд не запущен или слушает не тот порт. Проверить
ss -tlnpна сервере приложения. - 413 Request Entity Too Large. client_max_body_size слишком маленький. Поставить 100М и больше.
- 504 Gateway Timeout. Бэкенд тормозит. Увеличить proxy_read_timeout или чинить бэкенд.
- Битая кодировка в логах. Добавить proxy_set_header Accept-Charset utf-8 и charset utf-8 в server {}.
- Пустые X-Real-IP на бэкенде. Приложение не читает X-Forwarded-For или не настроен trust_proxy.
Настроим Nginx reverse proxy под ваши приложения
Ставлю Nginx перед любыми веб-сервисами: 1С-Битрикс, WordPress, Node.js, Python-бэкенды, корпоративные порталы. Настраиваю HTTPS, кеш, WebSocket, rate limiting. От 1 до 30 доменов, срок — от 1 рабочего дня.
Телефон: +7 903 729-62-41
Telegram: @ITfresh_Boss
Семёнов Евгений Сергеевич, директор АйТи Фреш
FAQ — частые вопросы по Nginx proxy
- Зачем нужен reverse proxy перед веб-приложением?
- Reverse proxy закрывает приложение от прямого доступа, терминирует SSL, раздаёт статику, кеширует ответы, балансирует нагрузку между бэкендами и унифицирует логи. Приложению не надо думать про TLS и сертификаты.
- Чем отличается forward от reverse proxy?
- Forward proxy защищает клиентов от прямого общения с внешними ресурсами (корпоративный squid). Reverse proxy защищает серверы: принимает клиентские запросы извне и направляет их к внутренним приложениям.
- Какие заголовки обязательно прокидывать?
- Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto. Без них бэкенд видит запросы от 127.0.0.1 и считает их небезопасными, логи теряют реальные адреса клиентов, а генерация ссылок ломается.
- Надо ли отдельно настраивать WebSocket?
- Да, нужно явно включить проксирование заголовков Upgrade и Connection, иначе Nginx разрывает соединение через 60 секунд. Ещё увеличить proxy_read_timeout до нужного значения.
- Какой буфер использовать под тяжёлые запросы?
- client_max_body_size должен покрывать максимальный размер загружаемого файла. По умолчанию 1 МБ — этого мало для большинства приложений. Ставлю 100М–1Г в зависимости от задачи.