· 15 мин чтения

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

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

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

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

Что такое reverse proxy? Это, по сути, сервер-посредник. Он встаёт между клиентами и вашими приложениями. Клиент «видит» только Nginx, а Nginx уже сам общается с приложением. Зачем это нужно? Плюсы такой схемы просты и абсолютно понятны:

У нас в ITFresh это аксиома: reverse proxy мы ставим перед 100% всех веб-приложений наших клиентов. Честно говоря, после многих лет опыта, никаких других рабочих вариантов я просто не вижу.

Установка Nginx под Debian/Ubuntu

В репозитории Ubuntu версия Nginx, к сожалению, часто отстаёт. А зачем нам устаревший софт, правда? Поэтому я всегда предпочитаю ставить его из официального репозитория 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

Случалось ли вам сталкиваться с тем, что Nginx внезапно "рвёт" WebSocket-соединение ровно через 60 секунд? Это частая проблема, когда приложение активно использует веб-сокеты: будь то Mattermost, Rocket.Chat, онлайн-чаты или админки на Node.js. Чтобы избежать таких неприятностей и досадных обрывов связи, я всегда добавляю либо отдельный location, либо включаю глобальную поддержку WebSocket.

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» каждую минуту.

Кеширование бэкенда

Ваше приложение отдаёт "тяжёлые" ответы, которые при этом редко меняются? Например, это списки товаров, RSS-ленты или API курсов валют. Тогда обязательно кешируем их в Nginx! Это заметно снижает нагрузку и ускоряет загрузку для пользователя.

# В 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, да ещё и система документооборота. И что самое удивительное: каждое из этих приложений сидело на своей отдельной виртуалке, и каждая такая виртуалка зачем-то занимала по ТРИ публичных 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 подписчика в целях рассылки информационных и рекламных материалов до момента отзыва согласия.