· 15 мин чтения

Nginx как reverse proxy: базовая настройка с нуля

Меня зовут Семёнов Евгений Сергеевич, директор АйТи Фреш. За 15+ лет я поставил Nginx в качестве reverse proxy, наверное, несколько сотен раз — перед 1С-Битрикс, WordPress, Nextcloud, GitLab, Mattermost, внутренними API на Node.js и Django. И каждый раз сталкиваюсь с тем, что типовая настройка в Интернете либо устарела, либо ломает половину приложений. Поэтому пишу свой рабочий конфиг, который проверен на продакшене.

Что такое reverse proxy и когда он нужен

Reverse proxy — это сервер-посредник между клиентами и вашими приложениями. Клиент видит Nginx, Nginx видит приложение. Плюсы простые и понятные:

У нас на практике 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.

Типовые грабли:

Настроим 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Г в зависимости от задачи.

Подпишитесь на рассылку ITfresh

Раз в неделю — практические гайды для руководителя IT и сисадмина: безопасность, 1С, миграции, резервные копии, лайфхаки из реальных проектов.

Реквизиты оператора персональных данных

ООО «АЙТИ-ФРЕШ», ИНН 7719418495, КПП 771901001. Юридический адрес: 105523, г. Москва, Щёлковское шоссе, д. 92, корп. 7. Контакт: info@itfresh.ru, +7 903 729-62-41. Оператор обрабатывает e-mail подписчика в целях рассылки информационных и рекламных материалов до момента отзыва согласия.