Структура конфигурации: контексты и директивы

Конфиг Nginx — это вложенные «коробки» (контексты), и настройка из внешней коробки наследуется во внутренние, пока её не переопределят.
«Понял контексты и наследование — понял 80% конфигурации Nginx. Остальное — это словарь директив.»

Вся настройка Nginx живёт в текстовых файлах, главный из которых — nginx.conf. Синтаксис простой и состоит из двух вещей: директивы (одна строка с точкой с запятой) и блоки (директива с фигурными скобками, открывающая контекст).

Директивы и блоки

Простая директива — это имя и значение: worker_processes auto;. Блочная директива открывает контекст и содержит внутри другие директивы:

worker_processes auto;          # простая директива (main-контекст)

events {                        # блок -> контекст events
    worker_connections 1024;
}

http {                          # контекст http
    server {                    # контекст server (виртуальный хост)
        listen 80;
        server_name example.com;
        location / {            # контекст location
            root /var/www/html;
        }
    }
}

Иерархия контекстов

Контексты вложены строго: main (самый верх, без скобок) содержит events и http; http содержит server-блоки; server содержит location-блоки. Визуально:

main
 |-- events { ... }
 |-- http {
 |     |-- server {        (один сайт)
 |     |     |-- location / { ... }
 |     |     +-- location /api/ { ... }
 |     +-- server { ... }  (другой сайт)
 |   }

Как работает под капотом: наследование

Многие директивы наследуются вниз: если ты задал gzip on; в контексте http, он действует во всех server и location внутри — пока какой-нибудь вложенный контекст не переопределит его своим значением. Это как переменные с областью видимости: внутренний контекст «перебивает» внешний. Поэтому общие настройки кладут повыше (в http), а частные — пониже (в конкретный location).

Важная тонкость: наследование работает по принципу «всё или ничего» для директив-массивов (например, add_header). Если ты добавил add_header в location, то заголовки из родительского контекста не подмешиваются — действуют только заголовки этого location. Это частый источник пропавших заголовков.

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

  • Забыть точку с запятой. Каждая простая директива заканчивается ;. Nginx не запустится и скажет, на какой строке проблема.
  • Ждать наследования add_header там, где его нет. Объявил add_header в location — родительские заголовки пропали. Дублируй явно.
  • Класть директиву не в тот контекст. worker_connections работает только в events, а root — в http/server/location, но не в events.

Best practices

  • Общие настройки — в http, специфичные — ниже. Меньше дублирования.
  • Разбивай конфиг на файлы и подключай через include /etc/nginx/conf.d/*.conf;.
  • Комментируй директивы через # — будущий ты скажет спасибо.

Как не утонуть в большом конфиге

Реальные конфигурации разрастаются: десятки сайтов, общие ssl-параметры, повторяющиеся блоки proxy_set_header. Чтобы не копировать одно и то же, Nginx даёт директиву include: общие куски выносят в отдельные файлы (например, snippets/ssl.conf или snippets/proxy.conf) и подключают одной строкой в нужных местах. Это и DRY, и единая точка правки: поменял параметры TLS в одном snippet — они применились ко всем сайтам.

Ещё одна вещь, экономящая часы, — переменные Nginx. Значения вроде $host, $request_uri, $remote_addr, $scheme доступны прямо в директивах и наполняются для каждого запроса. Именно из них собирают редиректы (return 301 https://$host$request_uri;) и заголовки для бэкенда. Понимание контекстов и переменных вместе даёт мысленную модель: «где объявить директиву, чтобы она подействовала там, где нужно, и нигде лишнего». Когда конфиг ведёт себя неожиданно, почти всегда дело в одном из двух: либо директива стоит не в том контексте, либо сработало (или не сработало) наследование. Держа в голове иерархию контекстов, ты диагностируешь такие случаи за секунды, а не методом проб и ошибок.

Итоги

Конфигурация Nginx — это вложенные контексты (main, events, http, server, location) с директивами внутри. Настройки наследуются сверху вниз и переопределяются в более глубоких контекстах. Особое внимание — к add_header, который наследование «обнуляет». Дальше разберём, где физически лежат эти файлы и как организовать их по-человечески.

Проверьте себя
1. Как соотносятся контексты в конфигурации Nginx?
AВсе директивы пишутся в один плоский список
BКонтексты вложены: main -> http -> server -> location, и настройки наследуются вниз
Cserver вложен в location
Devents вложен в http
2. Что произойдёт с родительскими `add_header`, если объявить `add_header` внутри location?
AОни добавятся к новым
BОни перестанут действовать в этом location — наследование add_header работает по принципу «всё или ничего»
CNginx не запустится
DОни продублируются дважды