nginx
Устройство конфига nginx, выбор server и location, root против alias, proxy_pass, проверка и перезагрузка
nginx — веб-сервер и обратный прокси. Конфиг состоит из вложенных блоков-контекстов; для каждого запроса nginx выбирает один server и внутри него один location, и уже их директивы решают, что ответить: отдать файл, вернуть код или передать запрос дальше.
Синтаксис
nginx [опции]
Опции командной строки
| Опция | Что делает |
|---|---|
| (без опций) | запустить; мастер-процесс уходит в фон |
-t | проверить конфиг и выйти: синтаксис, пути, сертификаты |
-T | то же и напечатать весь собранный конфиг со всеми include |
-s reload | перечитать конфиг без остановки: новые воркеры стартуют, старые дорабатывают запросы |
-s quit | плавно остановить — дождаться текущих запросов |
-s stop | остановить сразу |
-s reopen | переоткрыть файлы логов (после ротации) |
-c файл | взять другой главный конфиг |
-g 'директивы;' | добавить директивы верхнего уровня, например -g 'daemon off;' — не уходить в фон |
-v / -V | версия / версия, параметры сборки и модули |
-q | при -t показывать только ошибки |
Если nginx запущен как служба, то же самое делают systemctl reload nginx и systemctl restart nginx.
Структура конфига
Главный файл — /etc/nginx/nginx.conf. В Debian и Ubuntu он подключает conf.d/*.conf и sites-enabled/*; сайты кладут в sites-available/ и включают симлинком в sites-enabled/.
user www-data; # контекст main: процессы, логи
worker_processes auto;
events { worker_connections 768; }
http { # всё про HTTP
include mime.types;
access_log /var/log/nginx/access.log;
upstream backend { # группа серверов для proxy_pass
server 127.0.0.1:9000;
}
server { # один сайт
listen 8080;
server_name example.local www.example.local;
root /srv/site;
index index.html;
location / { # правила для части URL
try_files $uri $uri/ =404;
}
location /api/ {
proxy_pass http://backend/;
}
}
}
Каждая директива заканчивается ;. Директивы внешнего блока (root, index, access_log) наследуются вложенными, если те их не переопределяют.
Как выбирается server
- По
listen— адрес и порт, на которые пришло соединение. - Среди них — по заголовку
Hostиserver_nameв таком порядке: точное имя → самый длинный шаблон со звёздочкой в начале (*.example.com) → со звёздочкой в конце (www.example.*) → первая подошедшая регулярка (~^…$). - Ни одно не подошло —
serverсlisten … default_server, а без него первый описанный для этого порта.
server_name _; — просто имя, которое ни с чем не совпадёт; «ловушкой для всего» такой сервер делает именно default_server.
Как выбирается location
| Вид | Как работает |
|---|---|
location = /path | точное совпадение — выигрывает сразу |
location ^~ /path/ | префикс; если он самый длинный из префиксов, регулярки не проверяются |
location ~ regex / ~* regex | регулярка с учётом / без учёта регистра; первая подошедшая по порядку в файле |
location /path/ | обычный префикс; запоминается самый длинный, но регулярки его перебивают |
Порядок: точное совпадение → самый длинный префикс → если у него нет ^~, проверяются регулярки сверху вниз → если ни одна не подошла, остаётся самый длинный префикс.
Частые директивы
| Директива | Что делает |
|---|---|
listen 80; / listen 443 ssl; | порт (и адрес: listen 127.0.0.1:8080;); default_server — сервер по умолчанию для порта |
server_name a.com *.a.com; | имена сайта |
root /путь; | каталог с файлами: путь к файлу = root + URI |
alias /путь/; | замена префикса location на путь (только внутри location) |
index index.html; | какой файл отдавать на запрос каталога |
try_files $uri $uri/ /index.html; | проверить файлы по очереди, последний вариант — запасной (URI или =404) |
return 301 https://$host$request_uri; | сразу ответить кодом; для 3xx — адрес перехода, для 2xx/4xx — текст |
rewrite ^/old/(.*)$ /new/$1 permanent; | переписать URI регуляркой; permanent — 301, redirect — 302, last — искать location заново |
proxy_pass http://127.0.0.1:9000; | передать запрос другому серверу или upstream |
proxy_set_header Host $host; | заголовок, который уйдёт на бэкенд |
add_header X-Name value; | добавить заголовок в ответ |
allow 10.0.0.0/8; / deny all; | доступ по IP; проверяются по порядку |
auth_basic "текст"; + auth_basic_user_file файл; | парольная защита (файл формата htpasswd) |
error_page 404 /404.html; | своя страница ошибки |
autoindex on; | показывать список файлов каталога |
client_max_body_size 10m; | максимальный размер тела запроса; больше — 413 |
access_log / error_log | куда писать логи; access_log off; — не писать |
ssl_certificate / ssl_certificate_key | сертификат и ключ для listen … ssl |
include файл; | подключить другой файл (можно с шаблоном *) |
Переменные
| Переменная | Значение |
|---|---|
$uri | путь без параметров, после нормализации и rewrite |
$request_uri | исходный путь вместе с ?параметрами |
$args / $arg_имя | строка параметров / один параметр |
$host | имя хоста из запроса |
$remote_addr | IP клиента |
$scheme | http или https |
$http_имя | любой заголовок запроса: $http_user_agent |
root и alias, proxy_pass со слешем
| Конфиг | Запрос | Куда идёт |
|---|---|---|
location /static/ { root /srv/site; } | /static/a.css | файл /srv/site/static/a.css — root + весь URI |
location /files/ { alias /srv/files/; } | /files/a.txt | файл /srv/files/a.txt — префикс заменён |
location /api/ { proxy_pass http://backend/; } | /api/users | на бэкенд уходит /users — префикс заменён на / |
location /api/ { proxy_pass http://backend; } | /api/users | на бэкенд уходит /api/users — URI без изменений |
Логи
По умолчанию /var/log/nginx/access.log и /var/log/nginx/error.log. Строка access-лога (формат combined):
127.0.0.1 - admin [13/Oct/2026:15:24:29 +0000] "GET /pub/ HTTP/1.1" 200 412 "-" "curl/8.5.0"
IP клиента, пользователь Basic-авторизации, время, строка запроса, код ответа, размер тела, Referer, User-Agent. В error.log видно, какой файл nginx пытался открыть и почему не смог.
Примеры
# проверить синтаксис перед перезагрузкой — всегда
nginx -t && nginx -s reload
# какие listen и server_name реально попали в конфиг
nginx -T 2>/dev/null | grep -E '^\s*(listen|server_name)'
# включить сайт и применить
ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/
nginx -t && nginx -s reload
# запустить на переднем плане — видно ошибки старта
nginx -g 'daemon off;'
# слушает ли nginx нужный порт
ss -tlnp | grep nginx
# проверить виртуальный хост, подставив заголовок Host
curl -s -H 'Host: example.local' http://localhost:8080/
# файл паролей для auth_basic
printf 'admin:%s\n' "$(openssl passwd -apr1 'secret')" > /etc/nginx/.htpasswd
# следить за запросами и ошибками
tail -f /var/log/nginx/access.log /var/log/nginx/error.log
# самые частые коды ответов
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
Подводные камни
- Сначала
nginx -t.nginx -s reloadсо сломанным конфигом не применяет его: старые процессы продолжают работать со старым конфигом, а ошибку легко не заметить. Проверка показывает файл и строку ошибки. nginx -s reloadработает, только если nginx запущен: иначе ошибка про/run/nginx.pid. Повторныйnginxпри запущенном дастbind() … Address already in use.- Регулярка перебивает обычный префикс.
location /images/проигрываетlocation ~ \.png$для/images/a.png. Нужен приоритет префикса — пиши^~. - Слеши в
alias.location /files/сalias /srv/files;(без слеша в конце) превратит/files/a.txtв/srv/filesa.txt. Слеш в конце ставь и вlocation, и вalias— или не ставь нигде. rootвнутриlocationне обрезает путь.location /static/ { root /srv/site/static; }будет искать/srv/site/static/static/…. Это случай дляalias.- Слеш в
proxy_passменяет URI, который увидит бэкенд (см. таблицу выше). Бэкенд отвечает 404 на правильный, казалось бы, путь — проверь этот слеш. add_headerвlocationотменяет всеadd_headerуровнем выше, а не добавляется к ним. Заголовки, заданные вserver, пропадут в такомlocation.- 404 и 403 объясняет
error.log: там видно, какой именно путь на диске nginx пытался открыть и почему не смог (No such file or directory,Permission denied). Для403проверь права на каталоги по всему пути — пользователюwww-dataнуженxна каждом. - Нет
;— самая частая синтаксическая ошибка. Сообщение об ошибке указывает на строку после пропущенной точки с запятой. location = /exactне совпадает с/exact/— для точного совпадения важен каждый символ.