В этой статье погрузимся в основы конфигурации веб‑сервера Angie — директиву location. Она используется во всех конфигурациях при работе с HTTP‑модулем и отвечает за разделение настроек обработки запросов по URL. В том числе, с помощью location происходит разделение запросов на статические и динамические. Начнём с последнего: разберёмся, что такое динамические и статические запросы.

Навигация по циклу

  1. Почему стоит переходить на Angie

  2. Установка Angie из пакетов и в докере

  3. Переезд с Nginx на Angie. Пошаговая инструкция

  4. Настройка location в Angie. Разделение динамических и статических запросов.

Видеоверсия

Для вашего удобства подготовлена видеоверсия этой статьи, доступна на Rutube, VKVideo и YouTube.

Динамические и статические запросы

Стандартная архитектура веб‑приложения на сегодня включает в себя схему с обратным прокси (может называться «фронт‑сервер») и сервером приложений («бэкенд»). Например, это может быть связка Angie и PHP‑FPM.

В такой схеме фронт‑сервер обслуживает статические запросы — отдаёт файлы с диска, а бэкенд исполняет серверный код (например, PHP) и передаёт результат фронту для ответа клиенту.

Выделение location для статики

Со стороны клиента отличить статические и динамические запросы с гарантированной точностью невозможно, но можно предположить, что к статическим запросам для большинства веб-приложений можно отнести:

  • CSS файлы;

  • JS файлы;

  • файлы подключаемых шрифтов;

  • изображения;

  • аудио- и видеофайлы;

  • статические текстовые файлы (txt, html, xml);

  • прочие файлы для скачивания (архивы, бинарные файлы и т. д.)

Соответственно, для корректной конфигурации веб‑приложения в Angie необходимо выделить для всех этих категорий свои location, в которых будут определены правила обработки таких запросов. Например, если в приложении есть каталог /js, который содержит JS‑ресурсы, то его конфигурация может выглядеть так:

location /js/ {
  root /var/www/html;
}

Это так называемый префиксный location, то есть все запросы (если не будет более приоритетных location), адрес в которых начинается с /js/, будут обрабатываться с такой конфигурацией. Директива root здесь приведена для наглядности, на самом деле мы можем определить root на уровне сервера и оставить блок конфигурации пустым, так как значение директивы будет наследоваться с более высокого уровня.

В некоторых приложениях мы не можем полагаться на четкую структуру директорий и адресов ресурсов. Например, статические файлы могут находиться в любой точке адресной структуры приложения. В таком случае мы можем применить location на основе регулярных выражений (regex). Обычно определение статики работает на основе расширений файлов в URL:

location ~* \.(?:css|js|woff2?|jpe?g|gif|png|txt|pdf)$ {
  root /var/www/html;
}

В этом примере мы сопоставляем адрес ресурса с регулярным выражением без учёта регистра (~*), ищем в окончании адреса ($) знак точки (\.) и одно из расширений. Напоминаю, что GET‑параметры запроса не входят в адрес, то есть запрос /1.css?test=2 также попадёт в этот location.

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

Выделение location для динамики

Динамические запросы как правило определяются самым низкоприоритетным location /. Например:

location / {
   proxy_pass http://127.0.0.1:9090/;
}

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

location ~ \.php$ {
	fastcgi_pass unix:/run/php/php7.4-fpm.sock;
	fastcgi_index index.php;
	include fastcgi_params;
}

Попасть в такой location можно либо при прямом вызове скрипта (/info.php), либо при обработке запроса к директории (/shop/) с директивой index index.php. Однако в современных веб‑приложениях допустимы произвольные (человекочитаемые) URL, поэтому для них сложно составить правильный набор location, и становится сложно отличить статический запрос от динамического. Здесь на помощь приходит директива try_files, которая позволяет проверить наличие файлов на диске, соответствующих адресу в запросе и в случае их отсутствия отправить обработку в другой location или сразу на скрипт:

location / {
	try_files $uri $uri/ /index.php?$args;
}

location / {
try_files $uri $uri/ @bitrix;
}

location @bitrix {
        fastcgi_pass    127.0.0.1:9001;
        include fastcgi.conf;
}

В этих примерах запрос попадает в location /, там происходит попытка обработать запрос как URI, далее как директорию и дальше происходит внутреннее перенаправление на скрипт (/index.php?$args) или в именованный location (@bitrix).

Есть еще одна разновидность разделения динамических и статических запросов с использованием if. Использование блоков if в целом не рекомендуется из-за их непредсказуемого поведения в сочетании с директивами других модулей (не rewrite), но такая конструкция также возможна:

location / {
   root /var/www;
   index index.php;

   if (!-e $request_filename) {
      rewrite ^(.+)$ /index.php?q=$1 last;
   }
}

В примере выше происходит проверка наличия файла через if. Если файл есть, то он будет обслужен как статический запрос. Если файла нет, то запрос будет перенаправлен на /index.php?q=$1.

Для создания корректной конфигурации необходимо разобрать приоритеты различных типов location. Перейдём к разбору этого аспекта.

Приоритеты location

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

Типы location в Angie.

  1. Точный: location = /test/.

  2. Префиксный: location /test/.

  3. Префиксный без проверки регулярок: location ^~ /test/.

  4. Регулярное выражение без учета регистра: location ~* /test/.

  5. Регулярное выражение с учетом регистра: location ~ /test/.

  6. Именованный location: location @fallback.

Общий алгоритм поиска location состоит из следующих шагов.

  1. Поиск точного location (=).

  2. Если не нашли, ищем совпадения в префиксных location. Выигрывает самое длинное совпадение.

  3. Если не нашли или найденный location позволяет проверку регулярных выражений (то есть он не = и не ^~), проверяем регулярные выражения по очереди до первого совпадения.

  4. При совпадении используем найденный, иначе используем неявный location на текущем уровне.

Внутри регулярных выражений выигрывает первое совпадение, то есть важен порядок указания location в конфиге. В порядке приоритетов нет именованных location (@back), потому что в них попасть можно только в результате внутреннего перенаправления.

При выборе типов location нужно отдавать предпочтение префиксным location, так, как они более предсказуемы и проще проверяются процессором выражений. Если всё‑таки необходимо использовать регулярные выражения, то стоит добавить якори (— начало строки, $ — конец строки) для более точного поиска совпадений.

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

Копирование конфигурации в location

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

location /images/ {
	root /var/www;
	add_header Cache-Control "max-age=31536000, immutable";
}

location /css/ {
	root /var/www;
	add_header Cache-Control "max-age=31536000, immutable";
}

location /js/ {
	root /var/www;
	add_header Cache-Control "max-age=31536000, immutable";
}

location /files/ {
	root /var/www;
	add_header Cache-Control "max-age=31536000, immutable";
}

Как видно, в каждом location есть одинаковые директивы. Если root имеет одинаковые значения в рамках всего server, можно вынести эту директиву на уровень выше. Заголовок кэширования нужен только в статических location, поэтому для удобства вынесем его в отдельный файл и подключим с помощью include. Оптимизируем конфигурацию.

location /images/ {
	include /etc/angie/static.conf;
}

location /css/ {
    	include /etc/angie/static.conf;
}

location /js/ {
    	include /etc/angie/static.conf;
}

location /files/ {
   	include /etc/angie/static.conf;
}

Теперь можно вспомнить, что мы используем Angie, что позволяет нам сделать комбинированный location, сразу определив несколько location в одном блоке. Результат получается более удобочитаемым:

location /files/
    /css/
    /js/
    /images/ {
   	include /etc/angie/static.conf;
}

В этой конфигурации для изменения заголовка кэширования достаточно отредактировать файл /etc/angie/static.conf и обновить конфигурацию. При этом файл с заголовком можно использовать и в других блоках server.

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

Комментарии (7)


  1. php7
    02.06.2025 15:24

    Можно еще так:

    rewrite ^/blog/ /path/blog.php last;


  1. xitriy87
    02.06.2025 15:24

    А разве регулярные выражения не приоритетнее чем префиксные вхождения без = ?


    1. Nickmob Автор
      02.06.2025 15:24

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


  1. sirmax123
    02.06.2025 15:24

    Если есть отличия от nginx то хорошо бы акцентировать на этом внимание


    1. Nickmob Автор
      02.06.2025 15:24

      Так и сделано, комбинированные location есть только в Angie, о чем прямо написано в тексте.


      1. sirmax123
        02.06.2025 15:24

        Я подумал что есть еще отличия, спасибо за ответ

        Думаю ваша целевая аудитория знает как устроен nginx и как там настраивать location - повторять документацию nginx особого смысла вроде-бы нет


        1. Nickmob Автор
          02.06.2025 15:24

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