Директива 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 за порядком запису, і лише тоді звичайний префікс. Запам'ятовування цієї послідовності рятує від годин налагодження конфігурації.