Понимание структуры файла конфигурации Nginx и контекстов конфигурации

Вступление

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

Хотя многие пользователи знают о возможностях Nginx, новых пользователей часто смущают некоторые соглашения, которые они встречают в конфигурационных файлах Nginx. В этом руководстве мы сосредоточимся на обсуждении базовой структуры файла конфигурации Nginx вместе с некоторыми рекомендациями о том, как создавать свои файлы.

Понимание контекстов конфигурации Nginx

Это руководство расскажет об основной структуре, найденной в основном файле конфигурации Nginx. Расположение этого файла будет зависеть от того, как вы установили программное обеспечение на свой компьютер. Для многих дистрибутивов файл будет находиться в + / etc / nginx / nginx.conf +. Если он там не существует, он также может находиться в + / usr / local / nginx / conf / nginx.conf + или + / usr / local / etc / nginx / nginx.conf +.

Первое, что вы должны заметить при просмотре основного файла конфигурации, это то, что он выглядит организованным в виде древовидной структуры, определенной наборами скобок (которые выглядят как + {+ и +} + ). На языке Nginx области, которые определяют эти скобки, называются «контекстами», потому что они содержат детали конфигурации, которые разделены в соответствии с областью их интересов. По сути, эти подразделения обеспечивают организационную структуру вместе с некоторой условной логикой, чтобы решить, применять ли конфигурации внутри.

Поскольку контексты могут быть наслоены друг на друга, Nginx обеспечивает уровень наследования директив. Как правило, если директива действительна в нескольких вложенных областях, объявление в более широком контексте будет передано любому дочернему контексту в качестве значений по умолчанию. Дочерние контексты могут переопределять эти значения по желанию. Стоит отметить, что переопределение любых директив типа массива replace предыдущее значение, а не добавляется к нему.

Директивы могут использоваться только в тех контекстах, для которых они были разработаны. Nginx выдаст ошибку при чтении файла конфигурации с директивами, которые объявлены в неправильном контексте. Документация Nginx содержит информацию о том, в каких контекстах действует каждая директива, поэтому она очень полезна, если вы не уверены.

Ниже мы обсудим наиболее распространенные контексты, с которыми вы можете столкнуться при работе с Nginx.

Основные контексты

Первая группа контекстов, которые мы обсудим, - это основные контексты, которые Nginx использует для создания иерархического дерева и разделения проблем дискретных блоков конфигурации. Это контексты, которые составляют основную структуру конфигурации Nginx.

Основной контекст

Наиболее общий контекст - это «основной» или «глобальный» контекст. Это единственный контекст, который не содержится в типичных контекстных блоках, которые выглядят так:

# The main context is here, outside any other contexts

. . .

{

   . . .

}

Говорят, что любая директива, которая существует полностью вне этих блоков, обитает в «главном» контексте. Помните, что если ваша конфигурация Nginx настроена по модульному принципу, некоторые файлы будут содержать инструкции, которые, по-видимому, существуют вне контекста, заключенного в квадратные скобки, но которые будут включены в такой контекст, когда конфигурация сшита вместе.

Основной контекст представляет собой самую широкую среду для конфигурации Nginx. Он используется для настройки деталей, которые влияют на все приложение на базовом уровне. Хотя директивы в этом разделе влияют на более низкие контексты, многие из них не являются inherited, поскольку они не могут быть переопределены на более низких уровнях.

Некоторые общие детали, которые настраиваются в главном контексте, - это пользователь и группа для запуска рабочих процессов как, количество рабочих и файл для сохранения PID основного процесса. Вы даже можете определить такие вещи, как сходство рабочих процессоров и «приятность» рабочих процессов. Файл ошибок по умолчанию для всего приложения может быть установлен на этом уровне (это может быть переопределено в более конкретных контекстах).

Контекст событий

Контекст «событий» содержится в «основном» контексте. Он используется для установки глобальных параметров, которые влияют на то, как Nginx обрабатывает соединения на общем уровне. В конфигурации Nginx может быть только один контекст событий.

Этот контекст будет выглядеть следующим образом в файле конфигурации, вне любых других контекстов, заключенных в скобки:

# main context

events {

   # events context
   . . .

}

Nginx использует модель обработки соединений на основе событий, поэтому директивы, определенные в этом контексте, определяют, как рабочие процессы должны обрабатывать соединения. Главным образом, найденные здесь директивы используются либо для выбора метода обработки соединения, либо для изменения способа реализации этих методов.

Обычно метод обработки соединения выбирается автоматически в зависимости от наиболее эффективного варианта, доступного для платформы. Для систем Linux метод + epoll + обычно является лучшим выбором.

Другими элементами, которые можно настроить, является число соединений, которые может обрабатывать каждый работник, будет ли работник использовать только одно соединение за раз или будет принимать все ожидающие соединения после получения уведомления об ожидающем соединении, и будут ли работники по очереди реагировать на события ,

HTTP-контекст

При настройке Nginx в качестве веб-сервера или обратного прокси-сервера контекст http будет содержать большую часть конфигурации. Этот контекст будет содержать все директивы и другие контексты, необходимые для определения того, как программа будет обрабатывать соединения HTTP или HTTPS.

Контекст http является родственным контекстом событий, поэтому они должны быть перечислены рядом, а не вложенными. Они оба дети основного контекста:

# main context

events {
   # events context

   . . .

}

http {
   # http context

   . . .

}

В то время как нижние контексты более конкретны в отношении обработки запросов, директивы на этом уровне управляют значениями по умолчанию для каждого виртуального сервера, определенного в нем. Большое количество директив настраивается в этом контексте и ниже, в зависимости от того, как вы хотите, чтобы наследование функционировало.

Некоторые из директив, с которыми вы можете столкнуться, управляют местоположениями по умолчанию для доступа и журналами ошибок (+ access_log + и + error_log +), настраивают асинхронный ввод-вывод для файловых операций (+ aio +, + sendfile +, и + directio +), а также настроить состояния сервера при возникновении ошибок (+ error_page +). Другие директивы конфигурируют сжатие (+ gzip + и + gzip_disable +), тонкую настройку параметров поддержания активности TCP (+ keepalive_disable +, + keepalive_requests + и + keepalive_timeout +) и правила, которым Nginx будет следовать попытаться оптимизировать пакеты и системные вызовы (+ sendfile +, + tcp_nodelay + и + tcp_nopush +). Дополнительные директивы настраивают корневые и индексные файлы документа уровня приложения (+ root + и + index +) и настраивают различные хеш-таблицы, которые используются для хранения различных типов данных (+ * _ hash_bucket_size + и + * _ hash_max_size + `для + имя_сервера + , + типы + и + переменные + `).

Контекст сервера

Контекст «сервера» объявляется _в контексте «http». Это наш первый пример вложенных контекстов в квадратных скобках. Это также первый контекст, который допускает несколько объявлений.

Общий формат для контекста сервера может выглядеть примерно так. Помните, что они находятся в контексте http:

# main context

http {

   # http context

   server {

       # first server context

   }

   server {

       # second server context

   }

}

Причиной разрешения нескольких объявлений контекста сервера является то, что каждый экземпляр определяет определенный виртуальный сервер для обработки клиентских запросов. Вы можете иметь столько серверных блоков, сколько вам нужно, каждый из которых может обрабатывать определенное подмножество соединений.

Из-за возможности и вероятности использования нескольких серверных блоков этот тип контекста также является первым, что Nginx должен использовать алгоритм выбора для принятия решений. Каждый клиентский запрос будет обрабатываться в соответствии с конфигурацией, определенной в контексте одного сервера, поэтому Nginx должен решить, какой контекст сервера является наиболее подходящим, основываясь на деталях запроса. Директивы, которые решают, будет ли использоваться блок сервера для ответа на запрос:

  • * listen *: комбинация IP-адреса / порта, на которую предназначен этот блок сервера. Если клиент делает запрос, соответствующий этим значениям, этот блок потенциально будет выбран для обработки соединения.

  • * server_name *: эта директива является другим компонентом, используемым для выбора блока сервера для обработки. Если имеется несколько серверных блоков с директивами listen одинаковой специфичности, которые могут обработать запрос, Nginx проанализирует заголовок «Host» запроса и сопоставит его с этой директивой.

Директивы в этом контексте могут переопределять многие из директив, которые могут быть определены в контексте http, включая ведение журнала, корень документа, сжатие и т. Д. В дополнение к директивам, которые взяты из контекста http, мы также можем настроить файлы, чтобы попытаться ответить на запросы (+ try_files +), выпустить перенаправления и перезаписать (+ return + и + rewrite +) и установить произвольный переменные (+ set +).

Контекст местоположения

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

В то время как директивы, определяющие, следует ли выбирать блок сервера, определены на сервере context, компонент, который определяет способность местоположения обрабатывать запрос, находится в расположении definition (строка, которая открывает блок местоположения).

Общий синтаксис выглядит так:

location   {

   . . .

}

Блоки местоположения живут в контексте сервера и, в отличие от блоков сервера, могут быть вложены друг в друга. Это может быть полезно для создания более общего контекста местоположения, чтобы поймать определенное подмножество трафика, и затем дальнейшей обработки его на основе более определенных критериев с дополнительными контекстами внутри:

# main context

server {

   # server context

   location  {

       # first location context

   }

   location  {

       # second location context

       location  {

           # first nested location

       }

       location  {

           # second nested location

       }

   }

}

Хотя контексты сервера выбираются на основе запрошенной комбинации IP-адреса / порта и имени хоста в заголовке «Хост», блоки местоположения дополнительно разделяют обработку запроса в пределах блока сервера, просматривая URI запроса. URI запроса - это часть запроса, которая идет после комбинации имени домена или IP-адреса / порта.

Таким образом, если клиент запрашивает + http: // www.example.com / blog + на порту 80, + http +, + www.example.com + и порт 80 будут использоваться для определения того, какой сервер блок для выбора. После того, как сервер выбран, часть + / blog + (URI запроса) будет оцениваться по определенным местоположениям, чтобы определить, какой дополнительный контекст следует использовать для ответа на запрос.

Многие из директив, которые вы, вероятно, увидите в контексте местоположения, также доступны на родительских уровнях. Новые директивы на этом уровне позволяют вам достигать местоположений за пределами корня документа (+ alias +), помечать местоположение как только внутренне доступное (+ internal +) и использовать прокси для других серверов или расположений (используя http, fastcgi, scgi и uwsgi проксирование).

Другие контексты

Хотя приведенные выше примеры представляют основные контексты, с которыми вы столкнетесь в Nginx, существуют и другие контексты. Приведенные ниже контексты были выделены либо потому, что они зависят от дополнительных модулей, они используются только при определенных обстоятельствах, либо они используются для функциональных возможностей, которые большинство людей не будут использовать.

Мы не будем обсуждать каждый из доступных контекстов. Следующие контексты не будут обсуждаться более подробно:

  • * + split_clients + *: этот контекст настроен для разделения клиентов, которые получает сервер, на категории, помечая их переменными на основе процента. Затем их можно использовать для проведения A / B-тестирования, предоставляя разный контент разным хостам.

  • * + perl / perl_set + *: эти контексты настраивают обработчики Perl для местоположения, в котором они появляются. Это будет использоваться только для обработки с Perl.

  • * + map + *: Этот контекст используется для установки значения переменной в зависимости от значения другой переменной. Он обеспечивает отображение значений одной переменной, чтобы определить, какая вторая переменная должна быть установлена.

  • * + geo + *: Как и в предыдущем контексте, этот контекст используется для определения сопоставления. Однако это сопоставление специально используется для категоризации клиентских IP-адресов. Он устанавливает значение переменной в зависимости от подключаемого IP-адреса.

  • * + types + *: Этот контекст снова используется для отображения. Этот контекст используется для сопоставления типов MIME с расширениями файлов, которые должны быть связаны с ними. Обычно это обеспечивается с помощью Nginx через файл, который поступает в основной файл конфигурации + nginx.conf +.

  • * + charset_map + *: это еще один пример сопоставления контекста. Этот контекст используется для отображения таблицы преобразования из одного набора символов в другой. В заголовке контекста перечислены оба набора, и в теле происходит сопоставление.

Приведенные ниже контексты не так распространены, как те, которые мы обсуждали до сих пор, но все же очень полезно знать.

Восходящий контекст

Восходящий контекст используется для определения и настройки «восходящих» серверов. По сути, этот контекст определяет именованный пул серверов, к которым Nginx может затем обращаться к прокси-серверам. Этот контекст, вероятно, будет использоваться при настройке прокси разных типов.

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

# main context

http {

   # http context

   upstream  {

       # upstream context

       server ;
       server ;

       . . .

   }

   server {

       # server context

   }

}

Затем на восходящий контекст можно ссылаться по имени в пределах блоков сервера или местоположения, чтобы передавать запросы определенного типа в пул серверов, которые были определены. Затем восходящий поток будет использовать алгоритм (циклический перебор по умолчанию), чтобы определить, какому конкретному серверу передать запрос. Этот контекст дает нашему Nginx возможность балансировки нагрузки при прокси-запросах.

Почтовый контекст

Хотя Nginx чаще всего используется в качестве веб- или обратного прокси-сервера, он также может функционировать как высокопроизводительный почтовый прокси-сервер. Контекст, который используется для директив этого типа, называется, соответственно, «почтой». Контекст почты определяется в «основном» или «глобальном» контексте (вне контекста http).

Основная функция почтового контекста заключается в предоставлении области для настройки решения почтового прокси на сервере. Nginx имеет возможность перенаправлять запросы аутентификации на внешний сервер аутентификации. Затем он может предоставить доступ к почтовым серверам POP3 и IMAP для обслуживания фактических почтовых данных. Почтовый контекст также может быть настроен для подключения к SMTP Relayhost при желании.

В общем, почтовый контекст будет выглядеть примерно так:

# main context

events {

   # events context

}

mail {

   # mail context

}

Если контекст

Контекст «if» может быть установлен для обеспечения условной обработки директив, определенных в. Как и оператор if в обычном программировании, директива if в Nginx будет выполнять содержащиеся в нем инструкции, если данный тест возвращает «true».

Контекст if в Nginx предоставляется модулем перезаписи, и это основное предназначение этого контекста. Поскольку Nginx будет тестировать условия запроса со многими другими целевыми директивами, если * не * следует использовать для большинства форм условного выполнения. Это настолько важное замечание, что сообщество Nginx создало страницу под названием if is evil.

Проблема в основном в том, что порядок обработки Nginx очень часто может привести к неожиданным результатам, которые, похоже, подрывают значение блока if. Единственными директивами, которые считаются надежно безопасными для использования в этих контекстах, являются директивы + return + и + rewrite + (те, для которых этот контекст был создан). При использовании контекста if следует помнить, что он делает директиву + try_files + в том же контексте бесполезной.

Чаще всего if используется для определения необходимости перезаписи или возврата. Чаще всего они будут существовать в блоках расположения, поэтому общая форма будет выглядеть примерно так:

# main context

http {

   # http context

   server {

       # server context

       location  {

           # location context

           if () {

               # if context

           }

       }

   }

}

Контекст Limit_except

Контекст + limit_except + используется для ограничения использования определенных методов HTTP в контексте местоположения. Например, если только определенные клиенты должны иметь доступ к содержимому POST, но каждый должен иметь возможность читать содержимое, вы можете использовать блок + limit_except + для определения этого требования.

Приведенный выше пример будет выглядеть примерно так:

. . .

# server or location context

location /restricted-write {

   # location context

   limit_except GET HEAD {

       # limit_except context

       allow 192.168.1.1/24;
       deny all;
   }
}

Это будет применять директивы внутри контекста (предназначенные для ограничения доступа) при обнаружении любых методов HTTP *, за исключением *, перечисленных в заголовке контекста. Результатом вышеприведенного примера является то, что любой клиент может использовать глаголы GET и HEAD, но только клиенты из подсети + 192.168.1.1 / 24 + могут использовать другие методы.

Общие правила, которые необходимо соблюдать в отношении контекстов

Теперь, когда у вас есть представление об общих контекстах, с которыми вы, вероятно, столкнетесь при изучении конфигураций Nginx, мы можем обсудить некоторые рекомендации, которые следует использовать при работе с контекстами Nginx.

Применять директивы в самом высоком доступном контексте

Многие директивы действительны в более чем одном контексте. Например, существует довольно много директив, которые можно поместить в http, сервер или контекст местоположения. Это дает нам гибкость в настройке этих директив.

Однако, как правило, обычно лучше объявить директивы в самом высоком контексте, к которому они применимы, и переопределить их в более низких контекстах по мере необходимости. Это возможно из-за модели наследования, которую реализует Nginx. Есть много причин использовать эту стратегию.

Прежде всего, объявление на высоком уровне позволяет вам избежать ненужного повторения между контекстами родного брата. Например, в приведенном ниже примере каждое из местоположений объявляет один и тот же корень документа:

http {
   server {
       location / {
           root /var/www/html;

           . . .

       }

       location /another {
           root /var/www/html;

           . . .

       }

   }
}

Вы можете переместить корень в блок сервера или даже в блок http, например так:

http {
   root /var/www/html;
   server {
       location / {

           . . .

       }

       location /another {

           . . .

       }
   }
}

В большинстве случаев уровень сервера будет наиболее подходящим, но объявление на более высоком уровне имеет свои преимущества. Это не только позволяет вам устанавливать директиву в меньшем количестве мест, но также позволяет каскадно использовать значение по умолчанию для всех дочерних элементов, предотвращая ситуации, когда вы сталкиваетесь с ошибкой, забывая директиву на более низком уровне. Это может быть серьезной проблемой с длинными конфигурациями. Объявление на более высоких уровнях дает вам нормальный по умолчанию.

Использовать несколько контекстов братьев и сестер вместо логики If для обработки

Когда вы хотите обрабатывать запросы по-разному в зависимости от некоторой информации, которая может быть найдена в запросе клиента, часто пользователи переходят к контексту «если», чтобы попытаться обусловить обработку. Есть несколько вопросов, которые мы затронули ранее.

Во-первых, директива if часто возвращает результаты, которые не соответствуют ожиданиям администратора. Хотя обработка всегда приводит к одному и тому же результату при одном и том же входном сигнале, способ, которым Nginx интерпретирует среду, может сильно отличаться от того, который можно предположить без тщательного тестирования.

Вторая причина этого заключается в том, что уже существуют оптимизированные, специально разработанные директивы, которые используются для многих из этих целей. Nginx уже использует хорошо документированный алгоритм выбора для таких вещей, как выбор блоков сервера и блоков местоположения. Поэтому, если это возможно, лучше попытаться переместить различные конфигурации в их собственные блоки, чтобы этот алгоритм мог обрабатывать логику процесса выбора.

Например, вместо того, чтобы полагаться на перезаписи, чтобы получить пользовательский запрос в формате, с которым вы хотели бы работать, вы должны попытаться настроить два блока для запроса, один из которых представляет желаемый метод, а другой - перехватывает грязные запросы и перенаправляет (и, возможно, переписывает) их в ваш правильный блок.

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

Заключение

К этому моменту вы должны хорошо понимать наиболее распространенные контексты Nginx и директивы, которые создают блоки, которые их определяют.

Всегда проверяйте Nginx документацию для получения информации о том, в какие контексты можно поместить директиву, и для оценки наиболее эффективного местоположения. Забота при создании ваших конфигураций не только повысит удобство обслуживания, но и часто повысит производительность.

Related