Правила сопоставления location в Nginx на реальных примерах
Вы наверняка правили конфиг Nginx, перезагружали его и недоумевали, почему ваш блок location словно не применяется. Может быть, запрос к статическому файлу попадает в PHP-обработчик, или маршрут API поглощается catch-all. Виновником часто оказывается алгоритм сопоставления location в Nginx — он не так прост, как кажется.
В этом руководстве мы разберём, как Nginx выбирает блок location, с реальными примерами, которые вы можете проверить. К концу вы будете точно знать, какой блок побеждает и почему.
Как работает сопоставление location в Nginx
Когда приходит запрос, Nginx сравнивает URI со всеми определёнными блоками location. Процесс сопоставления следует определённому порядку:
- Точное совпадение (
=) — высший приоритет. Если найдено, Nginx останавливается и использует его. - Самое длинное префиксное совпадение — Nginx запоминает самый длинный совпавший префиксный location.
- Совпадение с регулярным выражением (
~или~*) — проверяются в порядке появления. Первое совпавшее регулярное выражение побеждает, переопределяя префиксное совпадение (если не используется^~). - Префиксное совпадение с
^~— если самый длинный совпавший префикс имеет^~, Nginx пропускает проверку регулярных выражений и использует его. - Если ни одно регулярное выражение не совпало, используется самое длинное префиксное совпадение.
Это основной алгоритм. Давайте посмотрим его в действии.
Модификаторы location: краткая справка
| Модификатор | Синтаксис | Тип совпадения | Приоритет |
|---|---|---|---|
= | location = /path | Точное | Наивысший |
^~ | location ^~ /path | Префиксное (без regex) | Высокий |
~ | location ~ \.php$ | Regex (с учётом регистра) | Средний |
~* | location ~* \.(jpg|png)$ | Regex (без учёта регистра) | Средний |
| нет | location /path | Префиксное | Низший |
Реальный пример 1: Статические файлы против PHP
Рассмотрим эту распространённую конфигурацию:
server {
listen 80;
server_name example.com;
location / {
root /var/www/html;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
}
Запрос к /index.php совпадает с регулярным выражением \.php$, поэтому он уходит в PHP-FPM. Запрос к /logo.png не совпадает с регулярным выражением, поэтому он возвращается к префиксу / и отдаёт статический файл. Просто, правда?
Но что если вы хотите отдавать /uploads/photo.php как статический файл (возможно, на самом деле это изображение)? Вы можете добавить точное совпадение:
location = /uploads/photo.php {
root /var/www/html;
}
Теперь это точное совпадение имеет приоритет над регулярным выражением.
Реальный пример 2: Маршрутизация API с префиксом и regex
Предположим, у вас есть API по пути /api/, и вы хотите проксировать все запросы к бэкенду, кроме проверки работоспособности, которая возвращает статический ответ.
location = /api/health {
return 200 "OK";
}
location /api/ {
proxy_pass http://backend;
}
location ~ ^/api/v[0-9]+/special {
proxy_pass http://special-backend;
}
Проследим /api/health: точное совпадение побеждает, возвращает 200. Для /api/users: нет точного, нет regex (не совпадает с special), поэтому используется самый длинный префикс /api/. Для /api/v1/special: регулярное выражение совпадает, поэтому оно переопределяет префикс и запрос идёт к special-backend.
Это демонстрирует, как regex может переопределить префиксное совпадение. Если вы хотите, чтобы префикс всегда побеждал, используйте ^~ вместо этого.
Реальный пример 3: Сила ^~
Представьте, что у вас есть директория /static/ с файлами, которые никогда не должны обрабатываться PHP, даже если они заканчиваются на .php. Использование ^~ гарантирует, что Nginx не проверяет regex-локации.
location ^~ /static/ {
root /var/www/html;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
Запрос к /static/script.php совпадает с префиксом ^~ /static/. Благодаря ^~ Nginx пропускает проверку regex и отдаёт файл напрямую. Без ^~ регулярное выражение совпало бы, и PHP-FPM выполнил бы его — потенциальный риск безопасности.
Распространённые ошибки и как их избежать
- Порядок regex имеет значение: Nginx проверяет regex-локации в порядке их появления в конфиге. Размещайте более специфичные шаблоны первыми.
- Отсутствие завершающих слэшей:
location /apiиlocation /api/— разные. Первый совпадает с/apiи/apix, а второй — с/api/и/api/users. Будьте точны. - Перекрывающиеся префиксы: Побеждает самый длинный префикс, поэтому
location /api/v1имеет приоритет надlocation /apiдля/api/v1/users. - Забыли
^~для статических ресурсов: Используйте его, чтобы regex не перехватывал запросы к статическим файлам. - Чувствительность к регистру:
~чувствителен к регистру,~*— нет. Используйте~*для расширений файлов.
Отладка сопоставления location
Если вы не уверены, какой location используется, включите отладочное логирование в Nginx. Добавьте error_log /var/log/nginx/error.log debug; в ваш server-блок, перезагрузите и проверьте лог. Вы увидите строки вроде test location: "/api/users" и using configuration "/api/".
Как вариант, временно используйте return 200 "matched: /api/"; в каждом location, чтобы увидеть, какой из них отвечает.
FAQ
Каков порядок приоритета модификаторов location в Nginx?
Точное совпадение (=) — наивысший, затем самый длинный префикс с ^~, затем regex (~ или ~*) по порядку, затем самое длинное префиксное совпадение без ^~.
Может ли regex-локация переопределить префиксную локацию?
Да, если только префиксная локация не использует ^~. Regex-локации проверяются после самого длинного префиксного совпадения, и если regex совпадает, он имеет приоритет над обычным префиксом.
Как настроить location только для конкретного файла?
Используйте точное совпадение с =, например, location = /favicon.ico. Это гарантирует совпадение только для этого точного URI.
Освойте свою конфигурацию Nginx
Понимание сопоставления location — ключ к надёжной настройке Nginx. Проверяйте свои конфиги с помощью nginx -t и используйте отладочные логи при сомнениях. Если вы работаете с логами Nginx и вам нужно анализировать шаблоны трафика, попробуйте наш Nginx Log Analyzer, чтобы быстро парсить и визуализировать ваши логи.