Директива location: матчинг и приоритеты по шагам

Рейтинг: 61% · 6 голосов
Самый подробный курс по Nginx - от первого конфига до production API-gateway. Архитектура и event loop, контексты и location, виртуальные хосты, статика, reverse proxy и upstream-балансировка, кэширование, HTTPS и TLS (post-quantum), HTTP/2 и HTTP/3 QUIC, безопасность и rate limiting, realip, JSON-логи и сквозная трассировка, метрики, тюнинг и траблшутинг. Плюс OpenResty (Lua, фазы, JWT, динамика) и Angie (нативные Prometheus, ACME, dynamic upstream). На основе эталонного gateway и лучших практик. Для новичков и SRE/DevOps. Актуально на 2026 (nginx 1.30/1.31, Angie, ingress-nginx EOL -> Gateway API).
Ответить
Аватара пользователя
Igor_NgINX
Сообщения: 44
Зарегистрирован: 11 май 2026, 05:31

Директива location: матчинг и приоритеты по шагам

Сообщение Igor_NgINX »

Оглавление курса (44)
  1. Что такое Nginx и почему он захватил веб
  2. Установка Nginx, Angie и OpenResty: пакеты, версии, Docker
  3. Первый конфиг с нуля: минимальный сервер за 5 минут
  4. Архитектура процессов: master, worker и event loop
  5. Анатомия конфигурации: контексты, наследование и модульность
  6. Виртуальные хосты: server и server_name
  7. Директива location: матчинг и приоритеты по шагам (вы здесь)
  8. Раздача статики: root, alias, try_files, sendfile
  9. Переменные, map и блок if
  10. rewrite, return и канонизация URL
  11. Работа с заголовками: add_header и proxy_set_header
  12. Модель доверия прокси-заголовков: realip и защита от спуфинга
  13. Сжатие: gzip, brotli и zstd
  14. Reverse proxy: proxy_pass и проброс запроса
  15. upstream и балансировка нагрузки
  16. Таймауты, повторы и устойчивость прокси
  17. FastCGI и PHP: nginx + PHP-FPM (и uwsgi/scgi)
  18. WebSocket, gRPC и стриминг через Nginx
  19. Кэширование ответов: proxy_cache и микрокэш
  20. HTTPS и TLS: сертификаты, протоколы, шифры (2026)
  21. Let's Encrypt и ACME: certbot, acme.sh, нативный ACME Angie
  22. HTTP/2 и HTTP/3 (QUIC) в 2026
  23. Безопасность: заголовки, скрытие версии, ограничения
  24. Rate limiting и защита от перегрузки
  25. Контроль доступа: allow/deny, auth_basic, auth_request и mTLS
  26. Логирование: access_log, форматы и структурированный JSON
  27. Сквозная трассировка запросов и OpenTelemetry
  28. Метрики и мониторинг Nginx
  29. Производительность и тюнинг под нагрузку
  30. Траблшутинг: 502, 504, 403, 404 и debug-лог
  31. OpenResty: Nginx как платформа на LuaJIT
  32. Фазы обработки запроса и Lua-хуки
  33. Lua API: ngx.*, shared dict, cosocket и lua-resty-core
  34. Практика OpenResty: авторизация, JWT, кэш, Redis
  35. Angie: современный форк Nginx 2026
  36. Динамическая конфигурация и service discovery
  37. Nginx как API-gateway и Kubernetes Gateway API
  38. Динамические модули, njs и WAF
  39. Stream-модуль: проксирование TCP и UDP
  40. Деплой, перезагрузка и конфиг как код
  41. Сценарий: статика, SPA и кэширование за CDN
  42. Сценарий: микросервисный gateway по образцу ngx-trace-gateway
  43. Капстоун: собираем production-gateway с нуля
  44. Чек-лист безопасности, CVE 2026 и аудит конфигурации
Боль, из-за которой ломаются конфиги: почему запрос ушёл не туда

Ты добавил блок для статики, перезагрузил nginx - и внезапно /api/v1/users отдаёт 404, хотя бэкенд жив. Или наоборот: ты закрыл /admin авторизацией, а злоумышленник зашёл через /admin.php в обход. В 9 случаях из 10 виновата не магия, а то, как nginx выбирает location. Это самая частая засада новичков и одновременно тема, на которой спотыкаются даже сеньоры, когда конфиг разрастается до сотни блоков.

Главная мысль урока: nginx не читает location-блоки сверху вниз и не берёт "первый подходящий". Порядок в файле для префиксов вообще не важен, а для regex - важен, но иначе, чем ты думаешь. Есть строгий алгоритм из четырёх шагов, и если ты держишь его в голове, nginx location перестаёт быть лотереей. Разберём механику до винтика, прогоним руками четыре URL и научимся ловить классическую ошибку, когда regex перехватывает запрос раньше нужного префикса.

Чтобы дальше всё было однозначно: location живёт внутри блока server (а иногда вложен в другой location), и матчинг идёт по нормализованному URI - без query string, после декодирования %XX и схлопывания /../ и //. То есть на /api/%2e%2e/secret?x=1 location видит уже /secret, а ?x=1 отброшен. Это важно: фильтровать query string внутри location бессмысленно, для этого есть $args и map. В эталонном ngx-trace-gateway ровно поэтому проверки SQLi/XSS по $query_string вынесены отдельно, а не навешаны на location.

Изображение

Пять с половиной типов location и что значит каждый модификатор

Запомни модификаторы - это половина успеха. Их ровно столько:
  • Префиксный (без модификатора): location /images/ - совпадает, если URI начинается с /images/. Это самый обычный тип. Таких блоков может совпасть несколько (например /, /images/, /images/avatars/), и nginx запомнит самый длинный.
  • = (точное совпадение): location = / - совпадает, только если URI равен строке буква-в-букву. Никаких "начинается с". Самый быстрый матч и самый высокий приоритет.
  • ^~ (префикс без regex): location ^~ /img/ - тоже префиксный, но с особым свойством: если этот блок оказался самым длинным префиксом, nginx не будет перебирать regex вообще. Это "стоп-сигнал".
  • ~ (regex, чувствительный к регистру): location ~ \.php$ - совпадает по регулярному выражению PCRE, A и a - разные буквы.
  • ~* (regex, нечувствительный к регистру): location ~* \.(jpg|png|css)$ - то же, но .JPG и .jpg равнозначны.
  • @ (именованный): location @fallback - вообще не участвует в обычном матчинге URL. В него нельзя попасть запросом снаружи, в него прыгают изнутри через try_files ... @fallback или error_page 500 @fallback.
Половинка - это @-локейшены: технически тоже location, но они стоят особняком, как в эталонном http_server.conf, где error_page уводит в @error404 и @error50x. Снаружи /@fallback недоступен.

Точный алгоритм выбора location: четыре шага, которые решают всё

Вот сердце урока. Nginx на каждый запрос выполняет ровно эту последовательность. Заучи её как таблицу умножения - это и есть nginx location order.
  • Шаг 1. Ищется точное совпадение по = . Если нашлось - немедленно стоп, этот location выигрывает, дальше ничего не смотрится. Поэтому location = / самый дешёвый: для корня сайта nginx не перебирает вообще ничего.
  • Шаг 2. Перебираются все префиксные блоки (обычные и ^~) и запоминается тот, чей префикс самый длинный (по числу совпавших символов). Порядок в файле тут не важен - nginx сравнивает длины. Просто запомнили кандидата, пока ничего не решили.
  • Шаг 3. Смотрим на запомненный префикс. Если он с модификатором ^~ - стоп, берём его, regex не трогаем. Если он обычный префиксный - идём дальше.
  • Шаг 4. Перебираются regex-блоки (~ и ~*) строго в порядке их записи в конфиге, сверху вниз. Первый совпавший выигрывает - и остальные regex уже не проверяются. Если ни один regex не совпал - возвращаемся к запомненному на шаге 2 префиксу.
Из этого вытекает таблица приоритетов, которую держи перед глазами:

Код: Выделить всё

= (точное)            <- абсолютный победитель, мгновенный стоп
^~ (самый длинный)    <- стоп, regex не смотрятся
~ / ~* (regex)        <- первый по порядку в файле
префикс (самый длинный) <- запасной вариант, если regex не сработал
Ключевой контринтуитив, на котором горят: обычный длинный префикс проигрывает короткому regex. Если у тебя есть location /api/v1/users/ (длинный префикс) и location ~ \.json$ (regex), то запрос на /api/v1/users/list.json уйдёт в regex, а не в твой аккуратный длинный префикс. Потому что шаг 4 перебивает шаг 2 для обычных префиксов. Спасает только ^~: переписав на location ^~ /api/v1/users/ ты на шаге 3 говоришь "стоп, regex не нужен".

nginx location примеры: пошаговый прогон четырёх URL

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

Код: Выделить всё

server {
    listen 80;
    server_name shop.local;
    root /var/www/shop;

    location = / {
        return 200 "EXACT root\n";
    }

    location / {
        return 200 "PREFIX slash (fallback)\n";
    }

    location /api/ {
        return 200 "PREFIX api\n";
    }

    location ^~ /img/ {
        return 200 "PREFIX-stop img\n";
    }

    location ~* \.(png|jpg|css)$ {
        return 200 "REGEX static\n";
    }

    location ~ ^/api/v1 {
        return 200 "REGEX api v1\n";
    }
}
Прогоняем. Я специально пишу рассуждение так, как его выполняет сам nginx.

URL 1: /
Шаг 1 - есть ли точное = / ? Да, location = / . Стоп. Победитель: EXACT root. Заметь: location / (обычный префикс) тоже подходит, но = всегда бьёт его и обрывает поиск мгновенно.

URL 2: /img/a.png
Шаг 1 - точного = /img/a.png нет. Шаг 2 - какие префиксы подходят? location / (длина 1) и location ^~ /img/ (длина 5). Самый длинный - /img/ . Шаг 3 - у запомненного префикса модификатор ^~ ? Да! Стоп, regex не смотрим вообще. Победитель: PREFIX-stop img. Обрати внимание: regex ~* \.png$ тоже подошёл бы, но ^~ не дал ему шанса. Это и есть смысл ^~ - защитить каталог от перехвата regex-ом.

URL 3: /api/v1/orders
Шаг 1 - точного нет. Шаг 2 - подходят / (длина 1) и /api/ (длина 5). Запоминаем /api/ как самый длинный, он обычный префикс (без ^~). Шаг 3 - он не ^~, идём дальше. Шаг 4 - перебираем regex по порядку: сначала ~* \.(png|jpg|css)$ - URI не оканчивается на эти расширения, мимо; затем ~ ^/api/v1 - совпадает! Стоп. Победитель: REGEX api v1. Вот он, классический случай: твой добротный префикс /api/ проиграл regex-у. Если бы ты этого не хотел, написал бы location ^~ /api/ .

URL 4: /style.css
Шаг 1 - точного нет. Шаг 2 - подходит только location / (длина 1), запоминаем. Шаг 3 - не ^~. Шаг 4 - regex по порядку: ~* \.(png|jpg|css)$ - оканчивается на .css, совпало! Стоп. Победитель: REGEX static. А location / остался лишь запасным вариантом, который не понадобился.

Проверить можно руками, не гадая:

Код: Выделить всё

$ curl -s http://shop.local/
EXACT root
$ curl -s http://shop.local/img/a.png
PREFIX-stop img
$ curl -s http://shop.local/api/v1/orders
REGEX api v1
$ curl -s http://shop.local/style.css
REGEX static
Четыре URL - четыре разных типа победителя. Если ты понял, почему каждый выиграл, ты понял nginx location матчинг целиком.

nginx location regex и вложенные блоки: тонкости эксплуатации

Несколько вещей, которые в брифе теории не видны, но бьют в проде.

Regex проверяются в порядке файла, и это единственный тип, где порядок решает. Если у тебя два пересекающихся regex - например ~* \.(jpg|jpeg)$ и ~* \.jpeg$ - то второй никогда не сработает, его съест первый. Поэтому более специфичные regex ставь выше общих. Для префиксов же порядок не значит ничего: можешь располагать их как удобно читать, nginx всё равно возьмёт самый длинный.

Вложенные location. location можно положить внутрь location. Это удобно: внешний ловит каталог, внутренний - частный случай. Алгоритм матчинга при этом запускается заново уже внутри выбранного родителя - и только по его потомкам.

Код: Выделить всё

location /download/ {
    internal;
    location ~* \.(zip|tar\.gz)$ {
        add_header Content-Disposition "attachment";
    }
}
Но осторожно: вложенный regex срабатывает, только если запрос сперва попал в родителя. Если снаружи в /download/ его перехватит другой regex верхнего уровня - до внутреннего дело не дойдёт. Вложенность не повышает приоритет, она лишь сужает область поиска.

Слеш и нормализация. location /api (без слеша) совпадёт и с /api, и с /apiary, и с /api/v1 - это просто префикс по символам, ему всё равно на границы пути. Если нужен именно каталог - пиши location /api/ со слешем. В эталонном проекте этот нюанс решён через map $uri в $needs_slash и канонизацию редиректами, чтобы /api и /api/ не плодили дублей для SEO и кэша.

Стоимость. Префиксный матч - это поиск по дереву, практически бесплатный даже на сотнях location. Regex - линейный перебор: каждый запрос гоняет PCRE по списку выражений сверху вниз, пока не совпадёт. На горячем пути (статика, health-check) ставь = или ^~, чтобы вообще не доходить до regex. И помни про CVE-2026-42945 в rewrite-модуле: чем меньше regex и rewrite в конфиге, тем меньше поверхность атаки и тем проще аудит.

Типичные грабли nginx location
  • Regex перехватил раньше нужного префикса. Самая частая. location /api/v1/users/ написан, а запросы на .json/.xml внутри него уводит общий regex статики. Лечение: либо ^~ на нужном префиксе, либо более узкий regex, либо вынести статику в отдельный каталог.
  • Думают, что location читается сверху вниз. Для префиксов - нет, берётся самый длинный независимо от позиции. Перестановка двух префиксных блоков ничего не меняет; перестановка двух regex - меняет всё.
  • Путают = и префикс. location = /health ловит ровно /health и ничего больше; location /health поймает ещё и /health-check, /healthz. Для эндпоинтов проверки всегда =, иначе случайно накроешь лишнее.
  • Обход через регистр и хвост. location ~ \.php$ (чувствительный к регистру) не поймает /shell.PHP, а апач за бэкендом - может выполнить. Для запрещающих правил по расширению бери ~* . Аналогично location = /admin не закроет /admin/ - это уже другой URI.
  • Забывают, что @-локейшен снаружи недоступен и наоборот. Нельзя сделать proxy_pass на /@backend запросом; @ - только цель для try_files и error_page.
Мини-лаба: собери и прогони руками

Десять минут, и алгоритм осядет в пальцах.
  • 1. Подними тестовый nginx (или контейнер openresty/openresty:latest) и создай server из примера выше, где каждый location делает return 200 со своим именем-ярлыком.
  • 2. Проверь синтаксис:

    Код: Выделить всё

    nginx -t
    и перезагрузи:

    Код: Выделить всё

    nginx -s reload
  • 3. Прогони все четыре curl из урока и сверь вывод с прогноном. Совпало - ты читаешь алгоритм правильно.
  • 4. Теперь сломай специально: поменяй location ~ ^/api/v1 на location ^~ /api/v1/ и снова дёрни /api/v1/orders. Должно стать PREFIX, а не REGEX - ты на шаге 3 включил стоп-сигнал.
  • 5. Поменяй местами два regex-блока и запроси /style.css . Убедись, что для regex порядок в файле решает (а для префиксов - проверь, что перестановка /api/ и /img/ ничего не меняет).
  • 6. Добавь location = /health { return 200 "ok"; } и запроси /health и /healthz - почувствуй разницу между точным и префиксным.
Контрольные вопросы
  • 1. Есть location / , location /static/ и location ~* \.css$ . Куда уйдёт запрос /static/app.css и почему именно туда?
  • 2. Чем поведение location ^~ /img/ отличается от location /img/ при наличии regex-блока на картинки? На каком шаге алгоритма разница?
  • 3. Два regex: ~ \.(gif|png)$ выше и ~ \.png$ ниже. Какой поймает /logo.png и почему второй бесполезен?
  • 4. Почему для эндпоинта /health правильнее location = /health , а не location /health ?
Итог

Location выбирается не по порядку в файле, а по алгоритму: точное = бьёт всё и обрывает поиск; иначе запоминается самый длинный префикс; ^~ на нём = стоп без regex; иначе перебираются regex сверху вниз и побеждает первый; и только если regex молчат - срабатывает запомненный префикс. Держи в голове таблицу = > ^~ > regex(по порядку) > префикс, помни про ловушку "regex перехватил префикс", закрывай горячие пути через = и ^~ - и nginx location перестанет тебя удивлять. В следующих уроках на этот скелет ляжет proxy_pass, try_files и кэш - но маршрут запроса всегда начинается здесь.
👍5 ❤️2 🔥2 😄 🤔2
Аватара пользователя
lorissa
Сообщения: 1
Зарегистрирован: 27 май 2026, 07:04

Re: Директива location: матчинг и приоритеты по шагам

Сообщение lorissa »

Вот этот прогон по четырём URL наконец вправил мне мозги. Раньше реально думал что сверху вниз читается и переставлял блоки наугад пока не заработает.
👍 ❤️2 🔥1 😄 🤔
Аватара пользователя
kiwo
Сообщения: 1
Зарегистрирован: 24 май 2026, 13:32

Re: Директива location: матчинг и приоритеты по шагам

Сообщение kiwo »

А правило про порядок regex относится только к ~ и ~* или к ^~ тоже? У меня два ^~ на /api/ и /api/v1/ - какой победит, тоже самый длинный?
👍 ❤️2 🔥 😄 🤔1
Ответить
← Предыдущая глава
Виртуальные хосты: server и server_name
Следующая глава →
Раздача статики: root, alias, try_files, sendfile

Все главы курса «Nginx профессионально: от первого конфига до API-gateway на OpenResty и Angie»

Поделиться темой: ✈ Telegram VK
Похожие запросы: Директива location в nginx: матчинг и приоритетыnginx rewrite и редиректыВиртуальные хосты nginx: server_name

Вернуться в «Nginx профессионально: от первого конфига до API-gateway на OpenResty и Angie»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя