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

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

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

Коротко

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

  • Вложенность: главный контекст → events и httpserverlocation. Каждый следующий сужает область действия.
  • Правило выбора: ставь директиву в самый узкий контекст, где она разрешена.
  • 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 велела бы браузеру месяц держать в кеше и главную страницу, и корзину.

Главное

Контексты вложены: главный → httpserverlocation, и каждый сужает область действия директивы. Ставь настройку в самый узкий контекст, где она разрешена; поднятая выше нужного, она однажды удивит человека, который добавит на сервер новый сайт.

Комментарии

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

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

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