Приоритеты и конфликты location в Nginx: полное руководство по настройке маршрутизации | AdminWiki

Приоритеты и конфликты location в Nginx: полное руководство по настройке маршрутизации

27 августа 2026 8 мин. чтения

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

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

Как Nginx выбирает location: алгоритм в деталях

При получении запроса Nginx выполняет пять последовательных шагов. Сначала он ищет точное совпадение URI с location, объявленным через модификатор =. Если такое совпадение найдено, поиск немедленно завершается, и используется именно этот блок. Точное совпадение имеет абсолютный приоритет над всеми остальными типами location.

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

Когда самый длинный префикс не имеет модификатора ^~, Nginx переходит к проверке регулярных выражений. Они проверяются строго в порядке их появления в конфигурационном файле. Первое совпавшее регулярное выражение побеждает и немедленно завершает поиск. Если ни одно регулярное выражение не совпало, используется запомненный ранее самый длинный префиксный location.

Точное совпадение (=) - наивысший приоритет

Модификатор = задает точное совпадение URI. Он полезен для конкретных путей, которые не должны обрабатываться другими правилами. Например, страница входа чаще всего находится по адресу /login, и для нее можно задать отдельный location:

location = /login {
    proxy_pass http://auth_service;
}

Запрос /login будет обработан именно этим блоком, даже если в конфигурации есть префиксный location / или регулярное выражение, подходящее под этот URI. Точное совпадение немедленно завершает поиск, поэтому его стоит использовать для критичных страниц: healthcheck-ов, точек аутентификации, служебных эндпоинтов.

Префикс с ^~ - приоритет над регулярными выражениями

Модификатор ^~ применяется к префиксному location и означает: если этот префикс выбран как самый длинный, регулярные выражения не проверяются. Это ключевой инструмент для защиты статических каталогов от перехвата динамическими правилами.

location ^~ /static/ {
    root /var/www;
}

Если в конфигурации есть регулярное выражение location ~ \.(css|js)$, оно не будет применено к запросу /static/style.css, потому что префикс ^~ /static/ выбран как самый длинный и блокирует проверку регулярных выражений. Это поведение критично для производительности: статические файлы не должны проходить через цепочку регулярных выражений.

Регулярные выражения (~ и ~*) - порядок имеет значение

Регулярные location объявляются с модификатором ~ для учета регистра и ~* без учета регистра. Порядок их следования в конфигурации определяет приоритет: первое совпадение останавливает поиск. Это отличает регулярные выражения от префиксных location, где выбирается самый длинный, а не первый.

location ~ \.php$ {
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}

location ~* \.(jpg|png|gif)$ {
    root /var/www/images;
}

Запрос /index.php совпадет с первым регулярным выражением, и обработка завершится. Запрос /photo.JPG совпадет со вторым, поскольку модификатор ~* игнорирует регистр. Если поменять эти блоки местами, поведение для PHP-файлов не изменится, но для изображений может измениться, если шаблоны пересекаются.

Обычный префикс - запасной вариант

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

location /api {
    proxy_pass http://backend;
}

Запрос /api/v1/users будет обработан этим location, если в конфигурации нет более специфичных правил. Обычный префикс хорошо подходит для корневых путей и fallback-сценариев, но его не стоит использовать для путей, которые могут пересекаться с регулярными выражениями.

Типичные конфликты location и их разрешение

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

Префикс /static/ против регулярного выражения \.(css|js)$

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

location /static/ {
    root /var/www;
}

location ~ \.(css|js)$ {
    proxy_pass http://asset_server;
}

Запрос /static/style.css будет обработан регулярным выражением, а не префиксом, потому что регулярные выражения проверяются после запоминания префикса, но до его применения. Решение: добавить ^~ к префиксному location:

location ^~ /static/ {
    root /var/www;
}

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

Несколько регулярных выражений: кто победит?

Когда несколько регулярных выражений подходят под один URI, побеждает первое по порядку в конфигурации. Это отличается от префиксных location, где выбирается самый длинный. Рассмотрим пример:

location ~ \.php$ {
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}

location ~* \.(php|html)$ {
    proxy_pass http://legacy_server;
}

Запрос /index.php совпадет с обоими регулярными выражениями, но обработан будет первым, потому что оно стоит раньше. Второе регулярное выражение никогда не получит PHP-файлы, если первое совпадает. Рекомендация: располагать более специфичные шаблоны раньше, а более общие позже. Если нужно, чтобы HTML-файлы обрабатывались legacy-сервером, а PHP-файлы через FastCGI, порядок должен быть именно таким, как в примере.

Точное совпадение против префикса: всегда выигрывает =

Точное совпадение имеет приоритет над любым префиксным location, даже если префикс длиннее. Это правило часто упускают из виду при проектировании конфигурации.

location = /admin {
    return 301 /admin/;
}

location /admin/ {
    proxy_pass http://admin_panel;
}

Запрос /admin без завершающего слэша будет обработан точным совпадением, которое выполняет редирект на /admin/. Запрос /admin/users совпадет с префиксным location и будет проксирован. Такая схема решает проблему дублирования страниц с разными URL и обеспечивает корректную обработку как корневого пути, так и вложенных.

^~ против регулярного выражения: блокировка проверки

Модификатор ^~ отменяет проверку регулярных выражений только если этот префикс выбран как самый длинный. Если есть более длинный префикс без ^~, регулярные выражения все равно будут проверены.

location ^~ /static/ {
    root /var/www;
}

location /static/js/ {
    proxy_pass http://js_builder;
}

location ~ \.js$ {
    proxy_pass http://cdn;
}

Запрос /static/js/app.js: самый длинный префикс - /static/js/, он не имеет ^~, поэтому Nginx переходит к проверке регулярных выражений. Регулярное выражение \.js$ совпадает и обрабатывает запрос. Префикс ^~ /static/ не блокирует проверку, потому что не он выбран как самый длинный. Чтобы гарантировать обработку статики без регулярных выражений, нужно добавить ^~ и к более длинному префиксу:

location ^~ /static/js/ {
    proxy_pass http://js_builder;
}

Практические рекомендации по организации location

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

Используйте ^~ для статических ресурсов

Статические файлы не должны проходить через цепочку регулярных выражений. Каждый запрос к изображению, CSS или JavaScript файлу, который обрабатывается регулярным выражением, потребляет CPU и увеличивает задержку. Модификатор ^~ гарантирует, что статика обрабатывается немедленно после выбора префикса.

location ^~ /static/ {
    root /var/www;
    expires 30d;
    add_header Cache-Control "public, immutable";
}

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

Порядок регулярных выражений: от частного к общему

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

# Сначала специфичные шаблоны
location ~ ^/api/v2/.*\.json$ {
    proxy_pass http://api_v2;
}

location ~ \.json$ {
    proxy_pass http://api_v1;
}

Запрос /api/v2/users.json совпадет с первым регулярным выражением и будет обработан API v2. Если поменять блоки местами, запрос уйдет на API v1, что приведет к ошибке. Правило простое: чем точнее шаблон, тем выше он должен быть в конфигурации.

Точные совпадения для критичных страниц

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

location = /healthcheck {
    access_log off;
    return 200 "OK";
}

Запрос /healthcheck всегда возвращает 200 без обращения к бэкенду и без записи в access-лог. Это полезно для систем мониторинга и балансировщиков нагрузки, которые проверяют доступность сервера. Точное совпадение исключает любые сюрпризы.

Отладка проблем с location

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

Проверка синтаксиса и логирование

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

nginx -t

Команда показывает синтаксические ошибки и предупреждения до перезагрузки Nginx. После проверки включите debug-лог для отслеживания выбора location:

error_log /var/log/nginx/debug.log debug;

Debug-лог содержит записи о том, какой location был выбран для каждого запроса, какие регулярные выражения проверялись и почему было принято то или иное решение. Для продакшена debug-лог следует включать только на время диагностики, поскольку он создает большую нагрузку на диск.

Тестирование с помощью curl

Чтобы быстро проверить, какой location обрабатывает конкретный URI, добавьте кастомный заголовок в каждый location и отправьте запрос через curl:

location = /login {
    add_header X-Location-Matched "exact-login";
    proxy_pass http://auth_service;
}

location ^~ /static/ {
    add_header X-Location-Matched "static-prefix";
    root /var/www;
}

Теперь запрос с curl покажет, какой блок сработал:

curl -I https://example.com/login

В заголовках ответа будет строка X-Location-Matched: exact-login. Это простой и надежный способ проверить маршрутизацию без чтения debug-логов. После завершения отладки кастомные заголовки можно удалить или оставить для внутренней диагностики.

Более глубокие методы диагностики маршрутизации, включая анализ access-логов и работу с модулем echo, описаны в руководстве по отладке маршрутизации Nginx. Если вы проектируете маршрутизацию для микросервисов, обратите внимание на конфигурации location, proxy_pass и rewrite для микросервисной архитектуры. Для комплексного подхода к маршрутизации на уровне приложений изучите практическое руководство по Nginx как L7-маршрутизатору.

Если вы разворачиваете Nginx на облачной инфраструктуре, Timeweb Cloud предоставляет готовые серверы и базы данных с гибким масштабированием для веб-проектов. Для работы с API и автоматизации задач маршрутизации можно использовать AiTunnel, агрегатор доступа к более чем 200 моделям нейросетей с оплатой в рублях.

Поделиться:
Сохранить гайд? В закладки браузера