Отладка маршрутизации Nginx: логгирование, проверка location и устранение ошибок | AdminWiki

Отладка маршрутизации Nginx: логгирование, проверка location и устранение ошибок

27 августа 2026 8 мин. чтения
Содержание статьи

Введение: системный подход к отладке маршрутизации

Проблемы с маршрутизацией в Nginx проявляются одинаково: запрос уходит не на тот бэкенд, возвращается 404, зацикливается редирект или теряется часть URI при проксировании. Причина всегда одна - сервер выбрал не тот location-блок, который вы ожидали, либо передал запрос дальше с искажением. Быстрый способ вернуть контроль - включить детальное логгирование, пометить каждый location маркером через модуль echo и прогнать запросы через curl. Дальше подключается ngxtop для наблюдения за потоком трафика в реальном времени.

Эта статья даёт пошаговый алгоритм диагностики. Сначала настраиваем логи так, чтобы видеть полный путь запроса. Затем проверяем фактический выбор location. После этого разбираем типичные ошибки в proxy_pass и rewrite. В конце - чек-лист, который сокращает время поиска сбоя с часов до минут. Материал рассчитан на DevOps-инженеров и системных администраторов, работающих с продакшен-конфигурациями.

Если вы только выстраиваете схему маршрутизации, начните с руководства по настройке Nginx как L7-маршрутизатора. Здесь же фокус на диагностике уже работающей или сломанной конфигурации.

Настройка детального логгирования для диагностики

Дефолтный формат access_log показывает минимум: IP, дату, метод, URI, код ответа. Для отладки маршрутизации этого недостаточно. Нужно видеть, какой апстрим фактически обработал запрос, сколько времени это заняло и какие заголовки передавались. Настройка собственного log_format решает задачу.

Конфигурация access_log: какие данные важны

Добавьте в блок http следующий формат:

log_format debug_fmt '$remote_addr - [$time_local] "$request" '
                    'status=$status bytes=$body_bytes_sent '
                    'uri=$request_uri upstream=$upstream_addr '
                    'rt=$request_time uht=$upstream_header_time '
                    'referer=$http_referer ua=$http_user_agent';

access_log /var/log/nginx/access.log debug_fmt;

Переменная $upstream_addr показывает адрес бэкенда, выбранного для проксирования. Если запрос ушёл не на тот сервер, вы увидите это сразу. $request_time и $upstream_header_time помогают отличить медленный бэкенд от медленной маршрутизации. $request_uri фиксирует исходный URI до любых rewrite-преобразований, что критично для диагностики искажений пути.

При ротации логов используйте отдельный файл для отладочного формата, чтобы не смешивать его с обычным трафиком. Для продакшена такой детальный формат включайте временно, на период диагностики, затем возвращайте стандартный.

Использование error_log для выявления ошибок маршрутизации

Уровни логирования в error_log: debug, info, notice, warn, error, crit. Для отладки маршрутизации включайте debug точечно, чтобы не завалить диск записями. Это делается так:

server {
    listen 80;
    server_name example.com;

    error_log /var/log/nginx/debug.log debug;

    location /api/ {
        error_log /var/log/nginx/api-debug.log debug;
        proxy_pass http://backend;
    }
}

В debug-логе Nginx пишет весь процесс выбора location: какие блоки проверялись, какой модификатор совпал, какие rewrite-правила применились. Типичные записи, на которые стоит обращать внимание: using configuration, test location, rewritten data. Ошибки вида upstream timed out или connect() failed указывают на проблемы с бэкендом, а не с маршрутизацией.

Детальный разбор логов с готовыми командами grep и awk есть в материале по практическому анализу логов Nginx и Apache.

Проверка выбора location с помощью модуля echo

Самый быстрый способ понять, какой location обработал запрос, - добавить в каждый блок директиву echo с уникальным маркером. Модуль ngx_http_echo_module выводит строку прямо в тело ответа. Запрос через curl покажет маркер, и вы мгновенно увидите фактический выбор.

Установка и настройка модуля echo

В Debian и Ubuntu модуль входит в пакет nginx-extras. Проверьте наличие:

nginx -V 2>&1 | grep -o http_echo_module

Если вывода нет, установите расширенную сборку:

apt install nginx-extras

Для CentOS и сборок из исходников модуль компилируется отдельно. Подробности подключения сторонних модулей без риска для продакшена разобраны в гиде по модулям Nginx.

Практический пример: добавление echo в location

Конфигурация с маркерами:

location / {
    echo 'MATCH: root location';
}

location /api/ {
    echo 'MATCH: api location';
}

location ~ \.php$ {
    echo 'MATCH: php regex location';
}

Проверка:

curl http://example.com/api/users
# Ответ: MATCH: api location

curl http://example.com/index.php
# Ответ: MATCH: php regex location

Метод временный. Перед выкладкой в продакшен маркеры удаляйте, иначе реальные ответы приложения подменятся отладочными строками.

Использование curl для тестирования маршрутизации

curl - основной инструмент проверки. Он показывает заголовки, коды ответа, цепочки редиректов и позволяет отправлять произвольные заголовки. Три опции закрывают 90% задач диагностики: -I, -L, -v.

Проверка заголовков и кодов ответа

Команда curl -I отправляет HEAD-запрос и выводит только заголовки:

curl -I http://example.com/api/health

В ответе смотрите: HTTP/2 200 или HTTP/1.1 404, заголовок Server, Location при редиректах, кастомные X-* заголовки, которые вы добавляли для отладки. Если бэкенд возвращает свой Server, а вы ожидали Nginx, значит запрос проксируется без подмены заголовков - это нормально, но полезно знать при диагностике.

Для проверки конкретного location с передачей заголовков:

curl -I -H "X-Debug: 1" http://example.com/api/users

Отслеживание редиректов с помощью curl -L

Цепочку редиректов показывает опция -L с выводом URL на каждом шаге:

curl -L -w '%{url_effective}\n' -o /dev/null http://example.com/old-path

Если URL повторяется или цепочка длиннее трёх переходов, вероятен цикл. Nginx в таких случаях возвращает ошибку ERR_TOO_MANY_REDIRECTS в браузере или обрывает соединение. Причина обычно в конфликте rewrite-правил: правило срабатывает повторно на уже изменённом URI. Подробный вывод curl -v покажет каждый запрос и ответ с заголовком Location.

Мониторинг трафика в реальном времени с ngxtop

ngxtop парсит access-лог и выводит агрегированную статистику в стиле top: самые частые запросы, распределение кодов ответа, топ IP-адресов. Инструмент полезен, когда нужно увидеть картину в целом, а не разбирать одиночный запрос.

Установка и базовое использование ngxtop

Установка через pip:

pip install ngxtop

Запуск с указанием файла лога:

ngxtop -l /var/log/nginx/access.log

Без аргументов ngxtop попытается найти лог автоматически. В выводе по умолчанию: количество запросов, процент от общего числа, метод, URI, код ответа. Для кастомного формата лога укажите его через опцию --format, иначе парсер не распознает поля.

Анализ проблемных запросов с помощью ngxtop

Фильтр по ошибкам 4xx и 5xx:

ngxtop -l /var/log/nginx/access.log -i 'status >= 400'

Группировка по URI для поиска самых проблемных эндпоинтов:

ngxtop -l /var/log/nginx/access.log -g 'request_uri'

Топ медленных запросов по времени ответа апстрима:

ngxtop -l /var/log/nginx/access.log -g 'upstream_addr' --filter 'upstream_response_time > 1'

Если в логе нет нужных полей, сначала добавьте их в log_format, как показано выше. ngxtop работает только с тем, что записано в файл.

Типичные ошибки конфигурации и их исправление

Большинство проблем маршрутизации сводится к трём классам ошибок: неправильный порядок location-блоков, неверный proxy_pass, конфликтующие rewrite-правила. Разберём каждый с симптомами и решением.

Неправильный порядок location-блоков

Симптом: запросы к /api/ обрабатываются корневым location и возвращают 404 или HTML вместо JSON. Причина: префиксный location / объявлен раньше и перехватывает запросы, если более специфичный блок не имеет модификатора ^~ или не является регулярным выражением.

Решение: используйте ^~ для префиксных блоков, которые должны остановить дальнейший поиск:

location ^~ /api/ {
    proxy_pass http://backend;
}

location / {
    root /var/www/html;
}

Модификатор ^~ говорит Nginx: если префикс совпал, не проверять регулярные выражения. Это устраняет неоднозначность.

Ошибки в proxy_pass: завершающий слэш и URI

Симптом: бэкенд получает неправильный путь, часть URI теряется или дублируется. Причина: разница между proxy_pass http://backend; и proxy_pass http://backend/;.

Без завершающего слэша Nginx передаёт URI целиком. С завершающим слэшем - заменяет совпавшую часть location на путь из proxy_pass:

location /api/ {
    # Запрос /api/users -> бэкенд получит /api/users
    proxy_pass http://backend;
}

location /api/ {
    # Запрос /api/users -> бэкенд получит /users
    proxy_pass http://backend/;
}

Проверяйте фактический путь на бэкенде через его access-лог или добавьте на бэкенд временный вывод request_uri.

Проблемы с rewrite и редиректами

Симптом: бесконечный цикл редиректов или потеря query-параметров. Причина: rewrite-правило срабатывает повторно на уже изменённом URI, либо флаг last заставляет Nginx заново проходить весь цикл выбора location.

Решение: используйте флаг break, чтобы остановить дальнейшую обработку rewrite-модуля в текущем location:

location /old/ {
    rewrite ^/old/(.*)$ /new/$1 break;
    proxy_pass http://backend;
}

Флаг permanent или redirect используйте для внешних редиректов, когда нужно изменить URL в браузере. Проверяйте цепочку через curl -L -v, чтобы увидеть каждый шаг и найти зацикливание.

Приоритеты location-блоков: как Nginx выбирает обработчик

Nginx выбирает location по строгому алгоритму. Сначала ищет точное совпадение с модификатором =. Затем проверяет префиксные блоки, запоминая самый длинный совпавший. Если среди них есть ^~, поиск останавливается. Иначе проверяются регулярные выражения в порядке объявления. Если регулярное выражение совпало, оно побеждает. Если нет - используется запомненный префиксный блок.

Модификаторы location: =, ^~, ~, ~*

МодификаторТипПриоритетКогда использовать
=Точное совпадение1 (высший)Для конкретных URI вроде /health
^~Префиксный с остановкой2Для каталогов, которые не должны перехватываться регулярками
~Регистрозависимое регулярное3Для шаблонов с учётом регистра
~*Регистронезависимое регулярное3Для шаблонов без учёта регистра
без модификатораПрефиксный4 (низший)Для корневого location /

Ошибка начинающих - ставить регулярное выражение и ожидать, что оно победит длинный префикс. На деле регулярка проверяется только если нет ^~ и нет точного совпадения. Порядок объявления регулярных выражений важен: первое совпавшее побеждает.

Практический пример: отладка выбора location

Конфигурация с несколькими блоками и маркерами:

location = /health {
    echo 'MATCH: exact health';
}

location ^~ /static/ {
    echo 'MATCH: static prefix';
}

location ~ \.(png|jpg)$ {
    echo 'MATCH: image regex';
}

location / {
    echo 'MATCH: root';
}

Тесты:

curl http://example.com/health
# MATCH: exact health

curl http://example.com/static/logo.png
# MATCH: static prefix (^~ остановил поиск до регулярки)

curl http://example.com/photo.png
# MATCH: image regex

curl http://example.com/other
# MATCH: root

Этот метод снимает все сомнения о фактическом выборе. Маркеры удаляются после завершения отладки.

Чек-лист: пошаговый алгоритм отладки маршрутизации

  1. Проверьте синтаксис конфигурации: nginx -t. Ошибки на этом этапе блокируют запуск и не требуют дальнейшей диагностики.
  2. Включите детальный log_format с $upstream_addr, $request_uri, $request_time и перезагрузите Nginx.
  3. Добавьте echo-маркеры во все location-блоки, участвующие в маршрутизации.
  4. Прогоните проблемный запрос через curl -I и curl -v. Зафиксируйте код ответа и заголовки.
  5. Если есть редирект, проследите цепочку через curl -L -w '%{url_effective}'.
  6. Запустите ngxtop с фильтром по статусу, чтобы увидеть масштаб проблемы.
  7. Проанализируйте error.log на уровне debug для проблемного location.
  8. Проверьте proxy_pass: наличие завершающего слэша, корректность upstream-адреса.
  9. Проверьте rewrite-правила на повторное срабатывание и циклы.
  10. Удалите отладочные маркеры и верните стандартный формат логов.

Для контроля состояния Nginx после исправлений настройте мониторинг ключевых метрик по шпаргалке из пяти метрик.

Заключение: системный подход экономит время

Отладка маршрутизации Nginx сводится к последовательности: логируй, помечай, тестируй, мониторь. Детальный access_log показывает фактический путь запроса. Echo-маркеры снимают вопрос о выборе location. curl проверяет заголовки и редиректы. ngxtop даёт общую картину. Разбор типичных ошибок в proxy_pass и rewrite закрывает оставшиеся случаи.

Применяйте этот алгоритм при каждом сбое маршрутизации. Время диагностики сокращается с часов до минут, а конфигурация становится предсказуемой. Перед обновлением Nginx или внесением изменений в продакшен используйте чек-лист резервного копирования, чтобы иметь возможность быстрого отката.

Поделиться:
Сохранить гайд? В закладки браузера