Skip to content

Concrete5 на русском языке

Понимание конфигурации 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 обеспечивает уровень директивного наследования. Как правило, если директива действительна во множестве вложенных областей, декларация в более широком контексте будет передана любому дочернему контексту в качестве значений по умолчанию. Контексты для детей могут переопределять эти значения по своему усмотрению. Стоит отметить, что переопределение к любым директивам типа массива заменит предыдущее значение, а не добавит к нему.

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

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

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


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

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


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

# Главный контекст здесь, снаружи других контекстов

. . .

context {

    . . .

}

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

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

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

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


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

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

# main context

events {

    # events context
    . . .

}

 

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

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

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

# main context

events {
    # events context

    . . .

}

http {
    # main context

    . . .

}

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

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

Server контекст


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

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

# main context

http {

    # http context

    server {

        # first server context

    }

    server {

        # second server context

    }

}

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

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

  • listen: комбинация ip address / port, для которой этот серверный блок предназначен для ответа. Если запрос выполняется клиентом, который соответствует этим значениям, этот блок будет потенциально выбран для обработки соединения.
  • server_name: эта директива другой компонент, используемый для выбора блока server для обработки. Если есть несколько серверных блоков с директивами listen (прослушивания) с той же специфичностью, которые могут обрабатывать запрос, Nginx будет анализировать заголовок «Host» запроса и сопоставлять его с этой директивой.

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

Location Контекст (местоположение)


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

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

Общий синтаксис выглядит следующим образом:

location match_modifier location_match {

    . . .

}

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

# main context

server {

    # server context

    location /подходящие/критерии {

        # первый location context

    }

    location /другие/критерии {

        # второй location context

        location nested_match {

            # первый вложенный location

        }

        location другие_вложенные {

            # второй вложенный location

        }

    }

}

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

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

Многие из директив, которые вы, вероятно, увидите в контексте location, также доступны на родительских уровнях. Новые директивы на этом уровне позволяют вам находить места вне корневого каталога (псевдоним), отмечать местоположение как внутренне доступное (внутреннее), так и прокси-сервер для других серверов или местоположений (с использованием 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: Это еще один пример контекста отображения. Этот контекст используется для сопоставления таблицы преобразования с одного набора символов на другой. В заголовке контекста перечисляются оба набора, а в теле отображаются.

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

Контекст Upstream


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

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

# main context

http {

    # http context

    upstream upstream_name {

        # upstream context

        server proxy_server1;
        server proxy_server2;

        . . .

    }

    server {

        # server context

    }

}

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

Mail Контекст (контекст почты)


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

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

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

# main context

events {

    # events context

}

mail {

    # mail context

}

Контекст If


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

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

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

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

# main context

http {

    # http context

    server {

        # server context

        location location_match {

            # location context

            if (проверочное_условие) {

                # if context

            }

        }

    }

}

Контекст Limit_except


Контекст limit_except используется для ограничения использования определенных HTTP-методов в контексте location. Например, если только определенные клиенты должны иметь доступ к содержимому 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, server или location. Это дает нам гибкость при настройке этих директив.

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

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

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

            . . .

        }

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

            . . .

        }

    }
}

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

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

            . . .

        }

        location /another {

            . . .

        }
    }
}

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

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

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

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

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

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

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

Заключение


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

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