Nginx: reverse proxy

Nginx в роли reverse proxy принимает внешние HTTP/HTTPS-запросы и перенаправляет их к внутреннему приложению (Node.js, Python, несколько upstream-серверов), добавляя SSL, кэширование и балансировку нагрузки.

Зачем нужно

Node.js нежелательно выставлять напрямую на 80/443 порт: это небезопасно, не поддерживает несколько доменов и не умеет обслуживать статику эффективно. Nginx выступает фасадом: принимает HTTPS, раздаёт статику, проксирует API на Node.js и балансирует нагрузку между несколькими инстансами.

Где используется

  • Node.js/Python API за Nginx: HTTPS-терминация + проксирование
  • Несколько приложений на одном сервере (разные домены)
  • Балансировка нагрузки между несколькими backend-серверами
  • Раздача статических файлов напрямую без обращения к приложению

Основной контент

Базовый reverse proxy для Node.js

# /etc/nginx/sites-available/myapp
server {
    listen 80;
    server_name api.example.com;
    return 301 https://$host$request_uri;   # редирект HTTP → HTTPS
}

server {
    listen 443 ssl http2;
    server_name api.example.com;

    # SSL (Let's Encrypt через certbot)
    ssl_certificate     /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;

    # Проксирование на Node.js
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;

        # WebSocket поддержка
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';

        # Передача реального IP клиента
        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_cache_bypass $http_upgrade;
        proxy_read_timeout 90s;
    }

    # Статические файлы — Nginx отдаёт напрямую
    location /static/ {
        alias /var/www/myapp/public/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

Балансировка нагрузки

upstream api_backend {
    least_conn;                           # алгоритм: наименее нагруженный
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
    server 127.0.0.1:3003;
    keepalive 32;                         # переиспользовать соединения
}

server {
    listen 443 ssl http2;
    server_name api.example.com;

    location / {
        proxy_pass http://api_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Несколько приложений на одном сервере

# Frontend (React)
server {
    listen 443 ssl http2;
    server_name example.com www.example.com;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    root /var/www/frontend/dist;
    index index.html;

    # SPA: все маршруты → index.html
    location / {
        try_files $uri $uri/ /index.html;
    }
}

# API
server {
    listen 443 ssl http2;
    server_name api.example.com;
    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
    }
}

Полезные команды

nginx -t                         # проверить конфиг (без применения)
nginx -s reload                  # перезагрузить конфиг без рестарта
systemctl status nginx
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log

Частые ошибки

  • Не передавать X-Forwarded-For — приложение видит IP Nginx, не реального клиента
  • Не настроить proxy_read_timeout — Nginx разрывает соединение при долгих запросах (дефолт 60s)
  • HTTPS-конфиг без ssl_protocols TLSv1.2 TLSv1.3 — поддержка устаревших TLS 1.0/1.1
  • Забыть nginx -t перед nginx -s reload — синтаксическая ошибка в конфиге роняет Nginx

Связанные темы

Ресурсы