~/guides/nginx-location-priority-explained

Nginx

Приоритет location в Nginx: почему новый блок никогда не срабатывает, как ожидалось

Реальный порядок проверки location-блоков в Nginx: точное совпадение, регулярные выражения, префиксы — и почему порядок в файле почти не важен.

Добавили новый 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 и трафик идет не туда — в девяти случаях из десяти виновато совпавшее раньше по приоритету регулярное выражение, а не порядок строк в файле.