Nginx: продвинутая конфигурация для боевых серверов

Nginx давно вышел за рамки «просто веб-сервера». Сегодня это reverse proxy, load balancer, кеширующий слой и SSL terminator в одном лице. Большинство руководств останавливаются на базовой настройке с server_name и proxy_pass, но в продакшене этого недостаточно. В этой статье разберём продвинутые техники, которые я использую на боевых серверах.
Upstream и балансировка нагрузки
Если у вас несколько инстансов приложения, Nginx может распределять трафик между ними через блок upstream. Три основных алгоритма: round-robin (по умолчанию, запросы по очереди), least_conn (запрос уходит серверу с наименьшим числом активных соединений), ip_hash (клиент всегда попадает на один сервер, полезно для sticky sessions).
В реальности серверы не всегда одинаковы. Можно задать вес, health checks и параметры отказоустойчивости:
upstream app_backend {
least_conn;
server 127.0.0.1:3001 weight=3;
server 127.0.0.1:3002 weight=1;
server 127.0.0.1:3003 weight=1 max_fails=3 fail_timeout=30s;
server 127.0.0.1:3004 backup; # только если основные недоступны
}
server {
listen 443 ssl http2;
server_name app.example.com;
location / {
proxy_pass http://app_backend;
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_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 2;
}
} Кеширование с proxy_cache
Кеширование ответов от backend — один из самых эффективных способов снизить нагрузку. Сначала определяем зону кеша в блоке http: proxy_cache_path /var/cache/nginx/app_cache levels=1:2 keys_zone=app_cache:10m max_size=1g inactive=60m use_temp_path=off;. Затем используем в location:
location /api/ {
proxy_pass http://app_backend;
proxy_cache app_cache;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 10m;
proxy_cache_valid 404 1m;
add_header X-Cache-Status $upstream_cache_status;
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
} Не всё нужно кешировать. POST/PUT/DELETE и запросы авторизованных пользователей следует пропускать через map и proxy_no_cache.
Заголовки безопасности
Правильные HTTP-заголовки — простой способ защитить пользователей:
server {
# HSTS — браузер запомнит, что сайт работает только по HTTPS
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# Защита от clickjacking
add_header X-Frame-Options "SAMEORIGIN" always;
# Запретить MIME-sniffing
add_header X-Content-Type-Options "nosniff" always;
# Referrer Policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Ограничить доступ к API браузера
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# Content Security Policy
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;" always;
} Важный нюанс: add_header в дочернем location перезаписывает заголовки из родительского server. Если добавляете заголовок в location — продублируйте остальные.
Rate limiting
Nginx имеет два механизма: limit_req (частота запросов) и limit_conn (число соединений).
http {
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login_limit:5m rate=1r/s;
limit_req_status 429;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
}
server {
limit_conn conn_limit 50;
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://app_backend;
}
location /api/auth/login {
limit_req zone=login_limit burst=5 nodelay;
proxy_pass http://app_backend;
}
} 
Сжатие: gzip и Brotli
Сжатие уменьшает объём передаваемых данных на 60-80%:
http {
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_types text/plain text/css text/javascript application/javascript
application/json application/xml image/svg+xml font/woff2;
# Brotli (нужен модуль ngx_brotli)
brotli on;
brotli_comp_level 6;
brotli_min_length 1024;
brotli_types text/plain text/css text/javascript application/javascript
application/json application/xml image/svg+xml font/woff2;
} Brotli и gzip можно включить одновременно. Nginx выберет Brotli, если браузер поддерживает его (заголовок Accept-Encoding: br).
Проксирование WebSocket
WebSocket начинается как HTTP-запрос с заголовком Upgrade, затем переключается на двунаправленный протокол. Nginx нужно явно передать заголовки апгрейда:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
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 3600s;
proxy_send_timeout 3600s;
}
} Без этих заголовков WebSocket-соединения будут обрываться сразу после handshake — одна из самых частых ошибок при настройке reverse proxy.
SSL/TLS: best practices
server {
listen 443 ssl http2;
server_name app.example.com;
ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
ssl_dhparam /etc/nginx/dhparam.pem;
} Генерация DH-параметров: sudo openssl dhparam -out /etc/nginx/dhparam.pem 4096. Редирект HTTP на HTTPS: server { listen 80; return 301 https://$host$request_uri; }.
Server hardening
Несколько важных настроек для укрепления сервера:
http {
server_tokens off; # скрыть версию Nginx
client_max_body_size 10m; # ограничить размер запроса
client_header_timeout 10s; # защита от Slowloris
client_body_timeout 10s;
send_timeout 10s;
reset_timedout_connection on;
keepalive_timeout 30s;
} Блокировка нежелательных ботов:
map $http_user_agent $bad_bot {
default 0;
"~*sqlmap" 1;
"~*nikto" 1;
"~*nmap" 1;
"~*masscan" 1;
}
server {
if ($bad_bot) { return 403; }
} Проверка и применение
Перед применением всегда проверяйте конфигурацию:
sudo nginx -t
sudo systemctl reload nginx
curl -I https://app.example.com Для проверки SSL используйте SSL Labs — цельтесь в оценку A+.
Заключение
Балансировка нагрузки, кеширование, rate limiting и заголовки безопасности — это не опциональные «улучшения», а необходимый минимум для продакшена. Начните с заголовков безопасности и TLS, затем добавьте rate limiting на критичные эндпоинты, а кеширование и балансировку подключайте по мере роста нагрузки. И главное правило: после каждого изменения — nginx -t и reload, никогда не restart.