1. 1
  2. 2
  3. 3
  4. 4

# теория · шаг 2 из 4

Контексты: http, server, location

Коротко

Контекст - это блок, внутри которого директива имеет право стоять. У каждой директивы свой список, и он написан в её карточке в документации.

  • Вложенность: главный контекст → events и http → server → location. Каждый следующий сужает область действия.
  • Правило выбора: ставь директиву в самый узкий контекст, где она разрешена.
  • directive is not allowed here - самая честная ошибка nginx: она называет и директиву, и строку.
  • nginx -t умеет сказать «syntax is ok» и тут же провалиться: синтаксис и смысл проверяются разными этапами.

Если разница между http и server очевидна - листай до «Теперь сам».

Сначала ответь сам

Лимит на размер загружаемого файла нужен только админке на /admin/. Куда поставить client_max_body_size 100m;?

Три места выглядят рабочими: http, server и location /admin/. Все три пройдут nginx -t. Разница появится через год, и её стоит увидеть заранее.

На что это похоже

Контексты - это уровни правил в здании.

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

Nginx устроен так же, с одной поправкой: уровень определяет не смысл правила, а область его действия. Одна и та же строка в http и в location делает одно и то же, но с разным охватом.

Механизм: шесть контекстов и что каждый значит

/etc/nginx/nginx.conf
# главный контекст: всё, что вне блоков - про процесс целиком
user www-data;
worker_processes auto;

events {                      # как принимать соединения
    worker_connections 4096;
}

http {                        # всё, что касается HTTP
    include mime.types;
    gzip on;

    server {                  # один сайт
        listen 80;
        server_name shop.local;

        location /images/ {   # одна группа адресов внутри сайта
            root /var/www;
        }
    }
}

stream { }                    # то же самое, но для TCP и UDP

Это образец целого nginx.conf, класть его вместо своего не надо: он показывает, как вложены блоки. Три строки в нём новые. worker_connections 4096 - сколько соединений (открытых каналов между клиентом и nginx) один воркер держит одновременно; число подбирают под нагрузку, умолчание - 512. include mime.types подключает файл, лежащий рядом с nginx.conf, - таблицу «расширение файла → тип содержимого»; путь без каталога nginx считает от /etc/nginx. А location /images/ отбирает адреса, которые начинаются с /images/; другие формы записи - в разделе про locationРазбирается в разделе 4, глава «Как выбирается location»: Пять форм записи location.

главный - процесс целиком events http - весь HTTP-трафик server - один сайт location одна группа адресов location ещё одна Чем глубже стоит директива, тем меньше страниц она затрагивает.
Каждый контекст сужает область действия. Директива в http достаёт до всех сайтов сервера, включая те, которых ещё нет.

stream стоит рядом с http, а не внутри: это отдельный мир для TCP и UDP - способов передачи данных, поверх которых едет и сам HTTP. Там нет ни URL, ни заголовков, ни location. Пустой stream { } проверку проходит, так что пример безвреден, а сам stream разобран в отдельном разделеРазбирается в разделе 14, глава «stream: TCP и UDP»: Что такое stream и чем он не HTTP.

Где ты этого не увидишь

В /etc/nginx/conf.d/*.conf блока http обычно нет - и это не ошибка. Файлы оттуда подключаются директивой include изнутри http в главном nginx.conf. Server-блок в таком файле уже находится внутри http, просто открывающая скобка написана в другом файле.

Правило

Ставь директиву в самый узкий контекст, где она разрешена. Каждая строка, поднятая выше необходимого, - это настройка, о которой однажды споткнётся человек, добавивший на сервер новый сайт.

Вернёмся к вопросу из начала урока. Правильный ответ - location /admin/. В http лимит применится ко всем сайтам сервера, включая будущие; в server - ко всем страницам этого сайта, в том числе к форме загрузки аватарки, где сто мегабайт не нужны и вредны.

Разбор: что говорит nginx, когда директива не там

/etc/nginx/conf.d/shop.confhttp
server {
    listen 80;
    worker_connections 512;
}
↳  выводnginx -t
nginx: [emerg] "worker_connections" directive is not allowed here in /etc/nginx/conf.d/shop.conf:3
nginx: configuration file /etc/nginx/nginx.conf test failed

Это самая приятная ошибка nginx: названа директива, названа строка, и строка на этот раз правильная. worker_connections живёт в events - она про то, как процесс принимает соединения, а не про конкретный сайт.

Обратная сторона: ошибку выдаёт только по-настоящему запрещённое место. gzip_types разрешена в http, server и location, поэтому написанная в server она возражений не вызовет - и не должна.

Разбор: где наивное правило подводит

Наивное правило: «прошёл nginx -t - значит, конфиг разобран и понят».

/etc/nginx/nginx.conf
http {
    server { listen 80; }
}
↳  выводnginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: [emerg] no "events" section in configuration
nginx: configuration file /etc/nginx/nginx.conf test failed

Две строки подряд говорят противоположное. Так и есть: синтаксис и смысл проверяются разными этапами. Сначала разбор текста - тут всё в порядке, обе конструкции языка на месте. Потом модули - части nginx, каждая со своими директивами, - смотрят на то, что получилось, и блок events оказывается обязательным.

Практический вывод: читать надо последнюю строку nginx -t, а не первую. syntax is ok в середине вывода ничего не обещает.

Второе, что ломает наивное правило: не всякая директива разрешена там, где хочется. set работает в server, location и if (блок-условие внутри server или location, со своими подвохамиРазбирается в разделе 13, глава «map вместо if»: Чем опасен if), но не в http. Вот что говорит nginx -t, если поставить set прямо в http:

↳  выводnginx -t
nginx: [emerg] "set" directive is not allowed here in /etc/nginx/nginx.conf:3

Причина не в прихоти: set выполняется при обработке запроса, а в http обработки ещё нет - там только настройка. Задать значение на уровне http можно директивой map, и именно поэтому она существует. Разберём её в уроке про переменные.

Что ломается без этого

  • Настройка расползлась на чужие сайты. Симптом: год спустя на сервере появился второй сайт, и у него внезапно чужой лимит на тело запроса или чужой add_header. Ищи в http то, что должно было лежать в server.
  • directive is not allowed here на директиве, которая точно нужна. Значит, выбран не тот уровень. Открой документацию на https://nginx.org/en/docs/ - у каждой директивы там карточка из строк Syntax:, Default: и Context:, и последняя перечисляет блоки, где директива разрешена. Это нормальный повод открыть документацию, а не признак незнания.
  • Настройка не действует, хотя написана. Проверь, не лежит ли она в файле, который подключается не туда, куда ты думаешь: include вставляет текст в то место, где стоит сам.

Зачем это в работе

Разбирать чужой сервер приходится чаще, чем настраивать свой. Первый вопрос при этом всегда один: «эта строка про весь сервер или про один сайт?»

Ответ читается по отступу, и это единственное, ради чего в конфиге нужны отступы: nginx на них не смотрит вообще. nginx -T печатает собранный конфиг с сохранением вложенности - по нему за минуту видно, какие настройки общие для всех сайтов, а какие местные.

Теперь сам

Три директивы и три места. Где каждой правильное?

1. gzip on; - сжимать ответы нужно на всех сайтах сервера.

В http. Это как раз тот случай, когда широкий контекст выбран осознанно: настройка касается всего HTTP-трафика и не создаёт сюрпризов.

2. ssl_certificate /etc/letsencrypt/live/shop.local/fullchain.pem;

В server. СертификатРазбирается в разделе 9, глава «Сертификат, цепочка и ключ»: Что лежит в двух файлах - файл, которым сайт доказывает браузеру, что он настоящий, - выдан на конкретное имя, и другому сайту он не подходит. В http его поставить можно, и это работает как значение по умолчанию, - но получится сервер, где новый сайт по умолчанию отдаёт чужой сертификат.

3. expires 30d; - кеширование на месяц для картинок и шрифтов.

В location, отобранном по расширению:

/etc/nginx/conf.d/shop.confhttp › server
location ~* \.(png|jpg|woff2)$ {
    expires 30d;
}

~* означает регулярку без учёта регистра, как читать такие шаблоны - в разделе про locationРазбирается в разделе 4, глава «Как выбирается location»: Пять форм записи location. В server строка expires велела бы браузеру месяц держать в кеше и главную страницу, и корзину.

Главное

Контекст определяет, где действует настройка и разрешена ли она вообще. Перед добавлением директивы найди нужный уровень: общий, http, server или location. Слишком широкая область действия затронет соседние сайты и маршруты, даже если проверяемый сейчас запрос работает правильно.

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

Комментарий появится после проверки. Email не публикуется. Войти, чтобы не вводить имя каждый раз.