Nginx config
Весь синтаксис конфигов Nginx на одной странице: контексты, location, проксирование, upstream, SSL, gzip, редиректы, логи и лимиты.
Nginx читает конфиг сверху вниз и собирает его из директив (одна строка = одна настройка) и блоков в фигурных скобках (контексты). Ниже — весь синтаксис на одной странице: всё объяснено прямо в комментариях рабочих конфигов.
Структура конфига
Конфиг состоит из директив и блоков. Главный файл обычно — /etc/nginx/nginx.conf.
# Это комментарий — начинается с решётки, до конца строки
# Простая директива: имя, значения через пробел, точка с запятой в конце
worker_processes auto; # auto = по числу ядер CPU
# Блочная директива (контекст): имя + фигурные скобки
events {
worker_connections 1024; # макс. соединений на один worker
}
# Директивы наследуются внутрь вложенных блоков и могут переопределяться
http {
sendfile on; # действует во всех server/location ниже
}
# Подключение других файлов (шаблон с * допустим)
include /etc/nginx/conf.d/*.conf;
Контексты (иерархия)
Контексты вложены друг в друга: main → events → http → server → location. Где директива стоит — там и действует.
# main — самый верхний уровень (без обёртки), глобальные настройки
user www-data; # от какого пользователя работают worker'ы
worker_processes auto;
error_log /var/log/nginx/error.log warn; # глобальный лог ошибок
events { # настройки обработки соединений
worker_connections 1024;
}
http { # всё, что касается HTTP/HTTPS
include /etc/nginx/mime.types;
default_type application/octet-stream;
server { # один виртуальный хост
listen 80;
server_name example.com;
location / { # правило для группы URL
root /var/www/html;
}
}
}
# Контекст stream { ... } (TCP/UDP-прокси) — отдельная история, тут не трогаем
Виртуальные хосты
Каждый server — отдельный сайт. Nginx выбирает его по паре listen + server_name.
# Сайт №1
server {
listen 80; # слушаем 80-й порт (HTTP)
server_name example.com www.example.com; # несколько имён через пробел
root /var/www/example;
}
# Сайт №2 на том же порту — различаются по server_name
server {
listen 80;
server_name blog.example.com; # точное имя
# server_name *.example.com; # маска: любой поддомен
# server_name ~^www\d+\.; # регексп (начинается с ~)
root /var/www/blog;
}
# Дефолтный сервер: ответит, если ни один server_name не подошёл
server {
listen 80 default_server; # пометка default_server
server_name _; # _ = заглушка, не валидное имя
return 444; # закрыть соединение без ответа
}
Раздача статики
Связка root, index и try_files — основа отдачи файлов с диска.
server {
listen 80;
server_name static.example.com;
root /var/www/site; # корень: URL /img/a.png ищется в /var/www/site/img/a.png
index index.html index.htm; # что отдавать при запросе каталога /
location /downloads/ {
# alias ЗАМЕНЯЕТ часть пути (в отличие от root, который ДОБАВЛЯЕТ)
# URL /downloads/file.zip -> /srv/files/file.zip
alias /srv/files/;
}
location / {
# пробуем по очереди: файл -> каталог -> запасной вариант
# $uri — текущий путь запроса
try_files $uri $uri/ =404; # если ничего нет — отдать 404
}
}
Location-блоки и приоритеты
Модификатор перед путём задаёт тип совпадения. Это самая частая путаница в Nginx.
server {
listen 80;
server_name example.com;
root /var/www/site;
# 1) Точное совпадение — высший приоритет, проверяется первым
location = /favicon.ico {
log_not_found off;
}
# 2) Префикс с ^~ — если совпал, регекспы дальше НЕ проверяются
location ^~ /assets/ {
expires 30d;
}
# 3) Регексп с учётом регистра (~) — проверяется по порядку в файле
location ~ \.(jpg|png|gif)$ {
expires 7d;
}
# 4) Регексп без учёта регистра (~*)
location ~* \.(css|js)$ {
expires 1d;
}
# 5) Обычный префикс — самый низкий приоритет, выбирается самый длинный
location / {
try_files $uri $uri/ =404;
}
}
# Итог приоритетов: = > ^~ > ~ / ~* (по порядку) > обычный префикс
Проксирование
Главная задача для бэкенда: proxy_pass перебрасывает запрос на приложение, а proxy_set_header передаёт ему правильные заголовки.
# Группа бэкендов (можно указать и один сервер)
upstream backend {
server 127.0.0.1:8000; # приложение на локальном порту
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend; # куда перенаправить запрос
# Передаём бэкенду реальные данные клиента
proxy_set_header Host $host; # исходный домен
proxy_set_header X-Real-IP $remote_addr; # IP клиента
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; # http или https
proxy_read_timeout 60s; # сколько ждать ответа бэкенда
}
# WebSocket-проксирование требует апгрейда соединения
location /ws/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Балансировка нагрузки
Несколько server внутри upstream — и Nginx распределяет запросы между ними.
upstream app_cluster {
# Метод балансировки (по умолчанию round-robin — по кругу)
# least_conn; # отдать туда, где меньше активных соединений
# ip_hash; # клиент всегда на один и тот же сервер (по IP)
server 10.0.0.1:8000 weight=3; # вес 3: получит втрое больше запросов
server 10.0.0.2:8000; # вес 1 по умолчанию
server 10.0.0.3:8000 backup; # резервный: только если упали основные
server 10.0.0.4:8000 down; # помечен выключенным
# max_fails / fail_timeout — когда считать сервер сломанным
# server 10.0.0.5:8000 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://app_cluster;
}
}
HTTPS / SSL
Слушаем 443-й порт с флагом ssl и указываем сертификат с ключом.
server {
listen 443 ssl; # HTTPS-порт с включённым SSL
listen [::]:443 ssl; # то же для IPv6
http2 on; # включить HTTP/2 (быстрее)
server_name example.com;
# Файлы сертификата (обычно от Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Разрешаем только современные протоколы
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
root /var/www/site;
}
# Отдельный server: весь HTTP-трафик гоним на HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri; # вечный редирект на https
}
Редиректы
Два инструмента: быстрый return и гибкий rewrite с регекспами.
server {
listen 80;
server_name old.example.com www.example.com;
# return — самый простой и быстрый способ
# 301 — постоянный редирект, 302 — временный
return 301 https://example.com$request_uri;
}
server {
listen 80;
server_name example.com;
# rewrite — переписывает URL по регекспу
# $1 — захваченная группа из скобок (...)
rewrite ^/old-blog/(.*)$ /blog/$1 permanent; # permanent = 301
# флаги rewrite:
# last — остановить и заново подобрать location
# break — остановить, остаться в текущем location
# redirect — внешний 302
# permanent — внешний 301
location /articles/ {
rewrite ^/articles/(\d+)$ /post?id=$1 last;
}
}
Заголовки
add_header добавляет HTTP-заголовки в ответ — обычно для безопасности и кэша.
server {
listen 443 ssl;
server_name example.com;
root /var/www/site;
# Заголовки безопасности
add_header X-Frame-Options "SAMEORIGIN"; # защита от кликджекинга
add_header X-Content-Type-Options "nosniff"; # не угадывать MIME-тип
add_header Referrer-Policy "no-referrer-when-downgrade";
# HSTS: браузер обязан ходить только по HTTPS (год)
# always — добавлять даже к ответам с ошибками (4xx/5xx)
add_header Strict-Transport-Security "max-age=31536000" always;
location /api/ {
# CORS: разрешить запросы с другого домена
add_header Access-Control-Allow-Origin "*";
proxy_pass http://127.0.0.1:8000;
}
}
Gzip и кэширование
gzip сжимает ответы, expires велит браузеру держать файлы в кэше.
http {
# Сжатие текстовых ответов
gzip on;
gzip_comp_level 5; # уровень 1..9 (баланс CPU/размер)
gzip_min_length 256; # не сжимать совсем мелочь
gzip_types text/plain text/css application/json
application/javascript text/xml; # какие типы сжимать
# gzip_vary on; # добавить заголовок Vary: Accept-Encoding
server {
listen 80;
server_name example.com;
root /var/www/site;
# Долгий кэш для статики с хэшем в имени
location ~* \.(css|js|png|jpg|woff2)$ {
expires 1y; # держать год
add_header Cache-Control "public, immutable";
}
# HTML не кэшируем — должен обновляться сразу
location = /index.html {
expires -1; # запретить кэш
}
}
}
Логи
Два журнала: access_log (все запросы) и error_log (ошибки и отладка).
http {
# Свой формат строки лога (имя main используем ниже)
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log main; # файл + формат
error_log /var/log/nginx/error.log warn; # уровень: debug<info<warn<error
server {
listen 80;
server_name example.com;
# Можно переопределить лог для конкретного сайта/location
access_log /var/log/nginx/example.access.log main;
location /health {
access_log off; # не засорять лог health-check'ами
return 200 "ok";
}
}
}
Ограничения
Защита от перегрузки и больших запросов: лимит частоты и размера тела.
http {
# Зона лимита частоты: 10 МБ памяти, не больше 10 запросов/сек с одного IP
# $binary_remote_addr — IP клиента в компактном виде
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
server {
listen 80;
server_name example.com;
# Максимальный размер тела запроса (для загрузки файлов)
client_max_body_size 20m; # больше 20 МБ -> ошибка 413
location /login {
# Применяем лимит; burst=20 — допустимый всплеск очереди
# nodelay — отдавать всплеск сразу, не растягивая
limit_req zone=mylimit burst=20 nodelay;
proxy_pass http://127.0.0.1:8000;
}
# Ограничение числа одновременных соединений с IP делается через
# limit_conn_zone + limit_conn (аналогично limit_req)
}
}
Типичный конфиг: SPA + API
Боевой шаблон: фронтенд-SPA отдаётся как статика, а запросы /api/ уходят на бэкенд.
upstream api_backend {
server 127.0.0.1:8000;
}
# HTTP -> HTTPS
server {
listen 80;
server_name app.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
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;
root /var/www/app/dist; # собранный фронтенд
index index.html;
client_max_body_size 25m;
gzip on;
gzip_types text/css application/javascript application/json;
# API уходит на бэкенд
location /api/ {
proxy_pass http://api_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 /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Главное правило SPA: любой неизвестный путь отдаёт index.html,
# чтобы клиентский роутер сам разобрал URL
location / {
try_files $uri $uri/ /index.html;
}
}