В этой статье разбирается порядок применения правил nginx для обработки путей, блоков location, условий if, директив rewrite и других директив и параметров. Значение порядка применения определяет, какое правило сработает первым. В общем случае, первое совпавшее правило применяется, и обработка на этом заканчивается.
1. Иерархия контекстов
http {
server {
location /path {
# Обработка запроса
}
}
}Порядок наследования:
Директивы в
http(самый низкий приоритет)Директивы в
server(переопределяют http)Директивы в
location(самый высокий приоритет)
2. Порядок выбора location блоков
2.1. Приоритеты типов location (от высшего к низшему)
# 1. Точное совпадение (=) - НАИВЫСШИЙ ПРИОРИТЕТ location = /exact/path { # Только для /exact/path } # 2. Приоритетный префикс (^~) location ^~ /static/ { # Любой путь, начинающийся с /static/ # Если совпало, регулярные выражения НЕ проверяются } # 3. Регулярные выражения (~ и ~*) - ПОРЯДОК ОБЪЯВЛЕНИЯ location ~ \.php$ { # регистрозависимый # Обрабатывается в порядке объявления } location ~* \.(jpg|png)$ { # регистронезависимый # Обрабатывается в порядке объявления } # 4. Стандартный префикс - САМЫЙ НИЗКИЙ ПРИОРИТЕТ location / { # Любой путь, начинающийся с / # Выбирается самый длинный совпадающий префикс }
2.2. Полный алгоритм выбора location
location = /exact { # Шаг 1: Проверка точных совпадений (=) # Если найдено - немедленное использование } location ^~ /prefix { # Шаг 2: Проверка приоритетных префиксов (^~) # Если найдено - регулярные выражения НЕ проверяются } location ~ \.php$ { # Шаг 3: Проверка регистрозависимых regex (~) # Проверяются в порядке объявления } location ~* \.html$ { # Шаг 4: Проверка регистронезависимых regex (~*) # Проверяются в порядке объявления } location / { # Шаг 5: Выбор префиксного совпадения # Выбирается самый длинный совпадающий префикс }
3. Обработка директивы if
3.1. Приоритет и порядок выполнения
# ВАЖНО: if выполняется ВНУТРИ выбранного location # НЕ влияет на выбор location location / { # 1. Сначала проверяются условия if if ($request_uri ~ ^/admin) { # 2. Если true - выполняются директивы внутри return 403; } # 3. Затем выполняется остальной код try_files $uri $uri/ /index.php; }
3.2. Правила выполнения if
# Избегайте if в location, если возможно! # if может создавать неожиданное поведение location / { # Правильное использование: проверка существования файла if (!-e $request_filename) { rewrite ^/(.*)$ /index.php?q=$1 last; } # Правильное использование: проверка переменных if ($http_user_agent ~ MSIE) { rewrite ^(.*)$ /msie/$1 break; } # ОПАСНО: try_files внутри if if ($request_uri ~ ^/test) { try_files $uri =404; # НЕ РАБОТАЕТ КАК ОЖИДАЕТСЯ } # ОПАСНО: proxy_pass внутри if if ($http_user_agent ~ iPad) { proxy_pass http://backend; # МОЖЕТ ВЫЗВАТЬ ОШИБКИ } }
4. Порядок обработки rewrite правил
4.1. Цикл обработки rewrite
server { # rewrite выполняется в таком порядке: # 1. Сначала server-level rewrite (в порядке объявления) rewrite ^/old/(.*)$ /new/$1 permanent; # Вне location location / { # 2. Затем location-level rewrite (в порядке объявления) rewrite ^/page/(.*)$ /index.php?page=$1 last; # 3. Затем обработка внутри блока try_files $uri $uri/ =404; } }
4.2. Флаги rewrite
# last - останавливает обработку, ищет новый location rewrite ^/old/(.*)$ /new/$1 last; # break - останавливает обработку, продолжает в текущем location rewrite ^/images/(.*)$ /files/$1 break; # redirect - возвращает 302 rewrite ^/old$ /new redirect; # permanent - возвращает 301 rewrite ^/old$ /new permanent;
5. Обработка query параметров
5.1. Сохранение параметров
# По умолчанию параметры сохраняются rewrite ^/page/(.*)$ /index.php?page=$1; # /page/123?x=1 → /index.php?page=123&x=1 # Удаление параметров (добавление ?) rewrite ^/page/(.*)$ /index.php?page=$1?; # /page/123?x=1 → /index.php?page=123 # Явное добавление параметров rewrite ^/page/(.*)$ /index.php?page=$1&foo=bar; # /page/123 → /index.php?page=123&foo=bar
5.2. Доступ к параметрам
# Переменные для работы с параметрами $args # Все параметры: "x=1&y=2" $query_string # То же, что $args $arg_<name> # Конкретный параметр: $arg_x = "1" # Изменение параметров location / { if ($arg_sort) { set $args "${args}&order=asc"; # Добавление параметра } }
6. Пример полной обработки запроса
# Запрос: GET /pin/123?x=1 HTTP/1.1 server { # ШАГ 1: Server-level обработка rewrite ^/old/(.*)$ /new/$1 permanent; # /pin/123?x=1 не совпадает # ШАГ 2: Выбор location (по приоритету) # Проверка точных совпадений location = /pin/123 { # НЕ СОВПАДАЕТ (разные пути) # ... } # Проверка приоритетных префиксов location ^~ /pin/ { # СОВПАДАЕТ! # ШАГ 3: Выполнение в location # Проверка if (выполняется после выбора location) if ($arg_x = "1") { # Если true return 410; # Возвращает 410 } # Если if не сработал try_files $uri $uri/ =404; } # Regex location (НЕ ПРОВЕРЯЮТСЯ из-за ^~) location ~ \.php$ { # ... } # Префиксный location (НЕ ПРОВЕРЯЕТСЯ) location / { # ... } }
7. Специальные случаи и исключения
7.1. Обработка error_page
error_page 404 /404.html; # Перенаправляет на указанную страницу # error_page выполняется ПОСЛЕ всех остальных правил location / { try_files $uri $uri/ =404; # Если файл не найден → error_page } location = /404.html { internal; # Только внутренние запросы }
7.2. Обработка try_files
location / { # try_files проверяет в указанном порядке try_files $uri $uri/ /index.php?$args =404; # 1. Существует ли файл $uri? # 2. Существует ли директория $uri/? # 3. Если нет - перейти на /index.php с параметрами # 4. Если и это не работает - вернуть 404 }
7.3. Приоритет внутренних перенаправлений
# Внутреннее перенаправление через X-Accel-Redirect # Имеет более высокий приоритет, чем обычные location location /protected/ { internal; root /secure; } location /download/ { # После выполнения PHP, если возвращен X-Accel-Redirect, # запрос перенаправляется в location /protected/ try_files $uri /download.php; }
8. Полный список приоритетов (от высшего к низшему)
1. location = /exact # Точное совпадение 2. error_page # Обработка ошибок (после основной обработки) 3. X-Accel-Redirect # Внутреннее перенаправление 4. location ^~ /prefix # Приоритетный префикс 5. location ~ \.php$ # Регулярные выражения (в порядке объявления) 6. location ~* \.jpg$ # Регулярные выражения (регистронезависимые) 7. location /longest/ # Стандартный префикс (самый длинный) 8. location / # Стандартный префикс (короткий) 9. try_files # Проверка наличия файлов 10. rewrite в server # Server-level rewrite 11. rewrite в location # Location-level rewrite 12. if внутри location # Условные проверки 13. return # Прямой возврат кода 14. proxy_pass # Проксирование 15. fastcgi_pass # PHP-FPM
9. Важные правила
# 1. Порядок объявления важен для regex location ~ \.php$ { ... } # Проверяется ПЕРВЫМ location ~ \.html$ { ... } # Проверяется ВТОРЫМ # 2. location = имеет наивысший приоритет, но только для точного пути location = / { ... } # Только для / location / { ... } # Для /, /index, /page, etc. # 3. ^~ отключает проверку regex location ^~ /admin/ { ... } # Все пути /admin/*, regex не проверяются # 4. Внутри location важна последовательность location / { # Сначала rewrite rewrite ^/page/(.*)$ /index.php?page=$1 last; # Потом if if ($arg_sort) { rewrite ^ /sort.php?$args break; } # Потом try_files try_files $uri $uri/ =404; # Потом proxy_pass proxy_pass http://backend; }
