Директива location определяет, какой блок конфигурации обработает конкретный URI внутри server block, описанного в статье о виртуальных хостах Nginx. Проблема в том, что location-блоков в одном сайте обычно несколько, и Nginx проверяет их не в порядке записи в файле, а по собственному алгоритму приоритета. Непонимание этого алгоритма — частая причина, почему правило вроде бы прописано, а не срабатывает.
Что делает директива location
Location сопоставляет URI запроса с шаблоном и, если совпадение найдено, применяет вложенные директивы: root, proxy_pass, try_files, заголовки и так далее. Один server block может содержать десятки location — для статики, для API, для админки, для конкретных расширений файлов.
Ключевая сложность в том, что несколько location могут одновременно подходить под один и тот же URI. Например, запрос /api/users/5 подходит и под location /api/, и под location ~ \.php$, если в пути встречается .php. Nginx должен выбрать один блок по строгим правилам.
Модификаторы location: =, ~, ~*, ^~ и без модификатора
Перед шаблоном location можно указать модификатор, который меняет тип сравнения и приоритет:
- location = /path — точное совпадение URI, самый высокий приоритет.
- location ^~ /path — префиксное совпадение с остановкой поиска регулярных выражений.
- location ~ /path — совпадение по регулярному выражению с учётом регистра.
- location ~* .php$ — совпадение по регулярному выражению без учёта регистра.
- location /path — обычное префиксное совпадение без модификатора.
Порядок проверки правил Nginx
Nginx проверяет location не сверху вниз по файлу, а по алгоритму с чётким приоритетом:
1. Точное совпадение: location = /path
2. Префиксные location, среди них выбирается самый длинный совпавший префикс
3. Если у выбранного префикса стоит модификатор ^~ — поиск останавливается здесь
4. Иначе Nginx проверяет location с регулярными выражениями ~ и ~* по порядку в файле
5. Если совпадение по regexp нашлось — используется оно
6. Если нет — применяется тот самый длинный префикс из шага 2
Из этого следует правило: regexp location срабатывают только если их не заблокировал ^~ на более длинном префиксе, и порядок записи regexp location в файле имеет значение — Nginx берёт первое совпавшее сверху вниз.
Таблица приоритетов модификаторов
| Модификатор | Тип сравнения | Приоритет |
|---|---|---|
| = | Точное совпадение URI | 1 — наивысший |
| ^~ | Префикс, блокирует regexp | 2 |
| ~ и ~* | Регулярное выражение | 3, по порядку в файле |
| без модификатора | Обычный префикс | 4 — низший |
Частые ошибки и конфликты правил
Классическая ошибка — location /images/ с обычным префиксом и рядом location ~* \.(jpg|png)$ для кэширования картинок. Если в /images/ лежат jpg-файлы, регулярное выражение победит префикс, даже если location /images/ записан раньше в файле — порядок в файле важен только для regexp-блоков между собой.
Вторая частая ошибка — забыть ^~ перед location для статики, из-за чего запрос к статическому файлу неожиданно попадает в regexp-блок с proxy_pass на PHP-FPM. Подробнее о передаче запросов на backend — в статье про reverse proxy на Nginx, а о финальной отдаче файлов — в статье об отдаче статики.
Практические примеры location
Типичный набор правил для сайта со статикой, API и редиректами, который также перекликается со статьёй про rewrite и return в Nginx:
location = /favicon.ico { access_log off; log_not_found off; }
location ^~ /assets/ { expires 30d; }
location ~* \.(css|js|woff2)$ { expires 7d; }
location /api/ { proxy_pass http://127.0.0.1:3000; }
location / { try_files $uri $uri/ /index.php?$args; }
Здесь /favicon.ico обрабатывается первым по точному совпадению, /assets/ с ^~ гарантированно не отдаётся regexp-блокам, а остальные regexp и общий location проверяются в порядке из алгоритма выше.
Как проверить, какой location сработал
Чтобы убедиться, что запрос попадает в нужный блок, добавьте временный заголовок add_header X-Location-Debug "имя блока"; в каждый спорный location и посмотрите заголовки ответа через curl -I. После правок обязательны nginx -t и systemctl reload nginx.
- Перечислите все location в server block и отметьте модификаторы.
- Проверьте, нет ли regexp-блока, который случайно перекрывает статику с ^~.
- Проверьте порядок regexp-location между собой — Nginx берёт первый совпавший.
- Прогоните nginx -t перед reload на боевом сервере.
Приоритет location в Nginx — не порядок в файле, а строгий алгоритм: точное совпадение, затем префикс с ^~, затем regexp по порядку записи, и только потом обычный префикс. Запоминание этой последовательности избавляет от часов отладки конфигурации.