Добавили новый location /api/v2/ в конфиг, перезагрузили nginx, а трафик по-прежнему идет в старый location /api/.Intuitively кажется, что nginx должен проверять блоки сверху вниз построчно, как обычный код. На деле логика совсем другая, и порядок объявления в файле почти ни на что не влияет.
Реальный алгоритм проверки location
server {
location = /health {
return 200 "ok";
}
location ^~ /static/ {
root /var/www;
}
location ~* \.php$ {
fastcgi_pass 127.0.0.1:9000;
}
location /api/ {
proxy_pass http://backend:8000;
}
}
Nginx проверяет location не в порядке следования в файле, а по типу совпадения, в такой последовательности:
| Шаг | Тип | Синтаксис | Что происходит при совпадении |
|---|---|---|---|
| 1 | Точное совпадение | location = /path |
Побеждает мгновенно, поиск прекращается |
| 2 | Префикс с приоритетом | location ^~ /path |
Побеждает, если это самое длинное совпадение среди ^~, регулярки не проверяются |
| 3 | Регулярное выражение | location ~ /regex или ~* /regex |
Проверяются по порядку в файле, первое совпавшее побеждает |
| 4 | Обычный префикс | location /path |
Побеждает самое длинное совпадающее префиксное значение |
Почему ^~ — это не просто более специфичный префикс
Модификатор ^~ не означает “проверь раньше остальных префиксов”. Он означает “если это самое длинное совпадающее префиксное правило среди правил с ^~, не утруждай себя проверкой регулярных выражений вообще”. Без ^~ даже самый длинный и специфичный обычный префикс всё равно проиграет любому совпавшему регулярному выражению.
Классическая ошибка с изображениями и API
location ~* \.(jpg|png|gif)$ {
expires 30d;
}
location /api/images/logo.jpg {
proxy_pass http://backend:8000;
}
Казалось бы, /api/images/logo.jpg — куда более специфичный путь, чем регулярка на расширение файла. Но регулярное выражение проверяется раньше обычного префикса и здесь выиграет оно, а не второй блок, — картинка уйдет в статику, а не на backend, если только не добавить ^~ к пути с API.
Как проверить, не гадая
Каждый раз пересчитывать приоритет в уме на боевом сервере — плохая идея. Nginx Location Priority Checker принимает список ваших location-блоков и тестовый URL, и сразу показывает, какой блок реально выиграет, без риска сломать что-то в проде экспериментами.
Итоговый чеклист
Location проверяются не по порядку в файле, а по типу совпадения: сначала точное через =, потом префикс с ^~, потом регулярки по порядку объявления, и только в последнюю очередь обычные префиксы по длине.
Модификатор ^~ не ускоряет проверку, а полностью отключает проверку регулярных выражений, если это правило оказалось самым длинным подходящим префиксом.
Если добавили новый location и трафик идет не туда — в девяти случаях из десяти виновато совпавшее раньше по приоритету регулярное выражение, а не порядок строк в файле.