Загрузка...
Загрузка...
Нашли баг, сбой или ошибку в работе reChecker? Есть предложение по улучшению? Напишите нам, чтобы мы проверили и исправили проблему в сервисе.
Полное руководство по настройке Nginx. Виртуальные хосты, SSL, проксирование, кэширование, безопасность. Практические примеры конфигов для разных проектов.
Быстрые определения и связанные понятия из SEO-глоссария reChecker.
SSL-сертификат — цифровой документ, обеспечивающий шифрование соединения между браузером и сервером. Без него браузер показывает «Не защищено».
Читать в глоссарии →Brotli — современный алгоритм сжатия от Google, заменяющий Gzip. Сжимает HTML/CSS/JS на 20-30% лучше. Поддерживается всеми современными браузерами.
Читать в глоссарии →Gzip — алгоритм сжатия для HTTP-передачи, уменьшающий размер HTML, CSS и JS файлов на 60-80%. Обязателен для быстрой загрузки сайта.
Читать в глоссарии →HTTP/2 — протокол передачи данных второго поколения. Ускоряет загрузку сайта за счёт мультиплексирования, сжатия заголовков и Server Push.
Читать в глоссарии →Просмотр PEM файлов онлайн: сертификаты X.509, приватные ключи, CSR. Форматы PEM и DER. Анализ без отправки на сервер.
БезопасностьПошаговая настройка HSTS для принудительного HTTPS. max-age, includeSubDomains, preload. Nginx, Apache, Cloudflare. Проверка и отладка.
РазработкаПолное руководство по .htaccess для Apache. Редиректы, rewrite правила, безопасность, кэширование, сжатие. Практические примеры для веб-разработчиков и SEO.
БезопасностьПошаговое руководство по установке бесплатных SSL-сертификатов Let's Encrypt на Apache и Nginx. Certbot, автообновление, wildcard. Практический гайд для веб-мастеров.
Поделитесь с коллегами или изучите другие материалы блога
Nginx обслуживает более 30% всех сайтов в интернете. Высокая производительность, предсказуемое потребление памяти и способность обрабатывать десятки тысяч одновременных соединений делают его стандартом де-факто для серьёзных веб-проектов. Однако между «установить Nginx» и «настроить Nginx правильно» лежит пропасть, в которую проваливаются даже опытные разработчики.
Эта статья — практическое руководство от базовой структуры конфигурации до продвинутых техник кэширования и защиты от DDoS. Если нужно быстро собрать конфиг под конкретную задачу, воспользуйтесь Генератором Nginx конфигурации на reChecker — он создаст оптимальную конфигурацию за несколько кликов.
Конфигурация построена на иерархии контекстов — вложенных блоков, каждый из которых отвечает за свою область. Главный файл расположен по пути /etc/nginx/nginx.conf:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log warn;
events {
worker_connections 1024;
multi_accept on;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Директива worker_processes auto создаёт по одному рабочему процессу на ядро CPU. Параметр worker_connections определяет максимум одновременных соединений на процесс, итого пропускная способность — worker_processes × worker_connections. Директива use epoll задаёт механизм мультиплексирования Linux (на FreeBSD — kqueue).
Директивы в родительском контексте наследуются дочерними и могут быть переопределены. Конфигурации сайтов выносятся в /etc/nginx/sites-available/ с символическими ссылками из /etc/nginx/sites-enabled/:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo nginx -s reload
Всегда выполняйте nginx -t перед перезагрузкой — синтаксическая ошибка может привести к остановке сервера.
Server block — аналог виртуального хоста Apache. Минимальная конфигурация:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com/public;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Параметр server_name принимает точные имена, маски и регулярные выражения. Приоритет: точное имя → маска в начале (*.example.com) → маска в конце (example.*) → регулярное выражение. Если ни один блок не совпал, запрос идёт в дефолтный сервер:
server {
listen 80 default_server;
server_name _;
return 444;
}
Код 444 — специфичный для Nginx ответ, который разрывает соединение без отправки заголовков. Полезно для блокировки запросов по IP-адресу.
Nginx отдаёт статические файлы значительно быстрее любого application-сервера:
location ~* \.(jpg|jpeg|png|gif|ico|webp|avif|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
location ~* \.(css|js)$ {
expires 7d;
add_header Cache-Control "public";
access_log off;
}
location ~* \.(woff2?|ttf|eot|otf)$ {
expires 365d;
add_header Cache-Control "public, immutable";
add_header Access-Control-Allow-Origin "*";
access_log off;
}
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
Параметр immutable в Cache-Control сообщает браузеру, что файл гарантированно не изменится — полностью исключаются повторные обращения к серверу. Разница между root и alias: первый добавляет путь location к корню, второй заменяет location целиком.
Для SPA-приложений необходим fallback:
location / {
try_files $uri $uri/ /index.html;
}
upstream node_backend {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
keepalive 32;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://node_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 Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Директива keepalive 32 поддерживает пул постоянных соединений к бэкенду. Заголовки Upgrade и Connection необходимы для WebSocket.
server {
listen 80;
server_name php-app.example.com;
root /var/www/php-app/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_read_timeout 300s;
}
location ~* /uploads/.*\.php$ {
deny all;
}
}
Unix-сокет вместо TCP даёт прирост производительности 5–10% за счёт отсутствия overhead TCP-стека.
upstream gunicorn_backend {
server unix:/run/gunicorn/app.sock fail_timeout=0;
}
server {
listen 80;
server_name python-app.example.com;
client_max_body_size 10M;
location / {
proxy_pass http://gunicorn_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;
}
location /static/ {
alias /var/www/python-app/staticfiles/;
expires 30d;
}
}
Для балансировки между бэкендами Nginx поддерживает round robin (по умолчанию), weighted round robin, least_conn (наименее загруженный) и ip_hash (привязка клиента к серверу).
Для проверки текущего сертификата используйте SSL Checker на reChecker.
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
sudo certbot renew --dry-run
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_dhparam /etc/nginx/dhparam.pem;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
}
OCSP Stapling устраняет необходимость для браузера самостоятельно проверять статус отзыва сертификата, ускоряя TLS-handshake на 100–300 мс. Вынесите общие SSL-параметры в /etc/nginx/snippets/ssl-params.conf и подключайте через include — не дублируйте в каждом server-блоке.
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://example.com$request_uri;
}
Оба варианта (www и non-www) должны иметь валидный SSL-сертификат — браузер проверяет его до получения инструкции перенаправления.
map $request_uri $redirect_url {
/old-page-1 /new-page-1;
/products/123 /catalog/item-123;
/about-us /company;
}
server {
if ($redirect_url) {
return 301 $redirect_url;
}
}
Директива map обрабатывается на этапе инициализации и не влияет на производительность даже при тысячах записей.
proxy_cache_path /var/cache/nginx/proxy
levels=1:2
keys_zone=proxy_cache:10m
max_size=1g
inactive=60m
use_temp_path=off;
server {
location / {
proxy_pass http://backend;
proxy_cache proxy_cache;
proxy_cache_valid 200 10m;
proxy_cache_valid 404 30s;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
proxy_cache_key "$scheme$request_method$host$request_uri";
add_header X-Cache-Status $upstream_cache_status;
}
location /api/ {
proxy_pass http://backend;
proxy_no_cache 1;
proxy_cache_bypass 1;
}
}
proxy_cache_use_stale при ошибке бэкенда отдаёт устаревшую версию вместо 502. Директива proxy_cache_lock on предотвращает thundering herd — только один запрос к каждому URL уходит на бэкенд, остальные ждут кэша.
fastcgi_cache_path /var/cache/nginx/fastcgi
levels=1:2 keys_zone=fcgi_cache:10m
max_size=512m inactive=30m;
map $request_uri $skip_cache {
default 0;
~*/wp-admin 1;
~*/cart 1;
~*/checkout 1;
}
server {
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_cache fcgi_cache;
fastcgi_cache_valid 200 10m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
}
}
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 256;
gzip_types text/plain text/css text/javascript
application/json application/javascript
application/xml image/svg+xml;
Уровень 5 — оптимальный баланс: 6–9 дают минимальный прирост при заметном росте нагрузки на CPU. Директива gzip_vary on добавляет Vary: Accept-Encoding для корректной работы с CDN.
Brotli обеспечивает на 15–25% лучшее сжатие по сравнению с Gzip:
brotli on;
brotli_comp_level 6;
brotli_min_length 256;
brotli_static on;
brotli_types text/plain text/css text/javascript
application/json application/javascript
application/xml image/svg+xml;
Директива brotli_static on отдаёт заранее сжатые .br-файлы — максимальное сжатие без нагрузки на CPU в рантайме.
Для проверки заголовков безопасности используйте инструмент Security Headers.
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
limit_req_status 429;
server {
limit_req zone=general burst=20 nodelay;
location /login {
limit_req zone=login burst=3 nodelay;
}
}
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;" always;
client_max_body_size 10m;
client_body_timeout 12s;
client_header_timeout 12s;
map $http_user_agent $bad_bot {
default 0;
~*sqlmap 1;
~*nikto 1;
~*scanner 1;
}
server {
if ($bad_bot) { return 403; }
}
location ~ /\.git { deny all; return 404; }
location ~* \.(env|ini|log|conf|bak|sql)$ { deny all; return 404; }
log_format detailed '$remote_addr [$time_local] "$request" '
'$status $body_bytes_sent rt=$request_time '
'urt=$upstream_response_time cs=$upstream_cache_status';
log_format json escape=json '{'
'"time":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"request":"$request",'
'"status":$status,'
'"request_time":$request_time,'
'"upstream_response_time":"$upstream_response_time"'
'}';
JSON-формат удобен для интеграции с ELK Stack и Loki + Grafana.
map $http_user_agent $loggable {
default 1;
~*monitoring 0;
~*UptimeRobot 0;
}
access_log /var/log/nginx/access.log detailed if=$loggable;
server {
listen 127.0.0.1:8080;
location /nginx_status {
stub_status on;
allow 127.0.0.1;
deny all;
}
}
Endpoint возвращает метрики: активные соединения, число запросов, соединения в состоянии чтения/записи/ожидания. Подключается к Prometheus через nginx-prometheus-exporter.
Самая частая ошибка — непонимание приоритетов. Nginx выбирает location в таком порядке:
= /exact — точное совпадение (наивысший приоритет)^~ /prefix — префикс с остановкой поиска regex/prefix — обычный префикс (наиболее длинный)sudo nginx -t # Проверка синтаксиса
sudo nginx -T # Полная конфигурация
sudo tail -50 /var/log/nginx/error.log
sudo ss -tlnp | grep nginx # Проверка портов
502 Bad Gateway — бэкенд недоступен. Проверьте, запущен ли процесс (systemctl status php8.3-fpm) и совпадают ли права на Unix-сокет.
413 Request Entity Too Large — превышен client_max_body_size, установите нужное значение в server или location.
Бесконечный цикл редиректов — конфликт между Nginx и приложением. Решение: редирект HTTP→HTTPS в отдельном server-блоке, а в основном блоке передавайте X-Forwarded-Proto:
server {
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
proxy_set_header X-Forwarded-Proto $scheme;
location / { proxy_pass http://backend; }
}
Permission denied — Nginx работает от пользователя www-data, который должен иметь права на файлы сайта:
sudo chown -R www-data:www-data /var/www/site
sudo find /var/www/site -type d -exec chmod 755 {} \;
sudo find /var/www/site -type f -exec chmod 644 {} \;
curl -I -H "Host: example.com" http://127.0.0.1
curl -I http://example.com
curl -H "Accept-Encoding: gzip" -I https://example.com
Конфигурация Nginx — непрерывный процесс. По мере роста нагрузки добавляются правила кэширования, ужесточаются политики безопасности, тонко настраиваются параметры проксирования.
Ключевые принципы:
nginx -t перед применением.include для выделения повторяющихся блоков в отдельные файлы.Для быстрого старта используйте Генератор Nginx конфигурации на reChecker — он создаст конфигурацию с учётом SSL, сжатия и заголовков безопасности. Проверяйте результат через SSL Checker и Security Headers, а для настройки Apache — генератор .htaccess.