Как проверить редирект в Nginx: curl -I, curl -L и заголовок Location | AdminWiki

Как проверить редирект в Nginx: curl -I, curl -L и заголовок Location

05 сентября 2026 14 мин. чтения
Содержание статьи

Как быстро проверить редирект в Nginx

Корректный редирект в Nginx подтверждают три признака: ожидаемый HTTP-код, правильное значение заголовка Location и конечный URL без циклов. Для быстрой проверки одного ответа используйте curl -I, а для прохождения всей цепочки добавьте -L.

curl -I https://example.com/old
curl -IL https://example.com/old

Первая команда отправляет HEAD-запрос и показывает заголовки исходного ответа. Вторая команда последовательно переходит по заголовкам Location и выводит заголовки всех ответов в цепочке. В первую очередь проверьте строку с кодом, значение Location и число переходов.

Проверяемый инвариант для каждого тестового URL выглядит так: исходный адрес получает ожидаемый код 301, 302, 307 или 308, заголовок Location ведет к нужному адресу, цепочка не повторяется, а конечный URL возвращает ожидаемый результат.

Минимальная команда curl -I для проверки заголовков

Команда curl -I URL запрашивает только заголовки ответа. Она экономит время, когда тело страницы не нужно загружать.

curl -I https://example.com/old

Пример результата:

HTTP/2 301
server: nginx
date: Sat, 05 Sep 2026 10:00:00 GMT
location: https://example.com/new
content-length: 0

Строка HTTP/2 301 показывает версию протокола и код ответа. В другой конфигурации вместо нее может быть HTTP/1.1 301 Moved Permanently. Заголовок server: nginx подтверждает ответ Nginx, но сам по себе не доказывает, что сработало нужное правило. Главный результат проверки находится в строке location.

У curl -I есть ограничение: он отправляет метод HEAD. Большинство веб-серверов обрабатывает HEAD так же, как GET, но приложение, прокси или отдельный обработчик может отвечать иначе. Если результат выглядит неожиданно, сравните его с обычным GET:

curl -i https://example.com/old

Ключ -i добавляет заголовки к ответу GET. Тело страницы при этом будет выведено в терминал, поэтому для больших ответов удобнее использовать вариант с сохранением заголовков и удалением тела:

curl -sS -D - -o /dev/null https://example.com/old

Каким должен быть корректный ответ

Код ответа выбирают по смыслу перенаправления:

КодНазначениеЧто проверить
301Постоянный перенос ресурсаАдрес больше не должен возвращаться к старому URL
302Временное перенаправлениеСтарый URL должен продолжать обслуживаться по исходному сценарию после отмены правила
307Временное перенаправление с сохранением метода и тела запросаPOST, PUT или другой метод не должен превращаться в GET при переходе
308Постоянное перенаправление с сохранением метода и тела запросаЦелевой сервер должен получать тот же метод и данные

Для обычного переноса страницы чаще используют 301. Временный сценарий обычно проверяют с кодом 302. Для API, загрузки файлов и форм, где сохранение метода имеет значение, проверяйте 307 или 308.

Значение Location должно совпадать с ожидаемой целью по четырем параметрам: схема, домен, порт и путь. Для URL с параметрами добавьте к проверке query string. Например, если запрос был https://example.com/old?page=2, выясните, должен ли целевой адрес сохранить page=2.

HTTP/2 301
location: https://example.com/new?page=2

Ответ 200 вместо ожидаемого редиректа означает, что запрос обработал контент или приложение. Правило перенаправления не сработало либо запрос попал в другой server или location. Код 404 указывает на отсутствие ресурса или неверный маршрут, а 500 и 502 требуют проверки приложения, upstream и журналов.

Как проверить редирект через curl -L и увидеть цепочку

Ключ -L заставляет curl переходить по каждому полученному Location. Один вызов с -L помогает узнать конечный результат, но для диагностики нужно сохранить промежуточные заголовки.

Показать все промежуточные ответы

Для цепочки редиректов используйте curl -IL:

curl -IL https://example.com/old

Условный вывод может выглядеть так:

HTTP/2 301
location: https://example.com/old

HTTP/2 301
location: https://www.example.com/old

HTTP/2 200
content-type: text/html

В этом примере запрос проходит два перенаправления: сначала меняется схема, затем домен. Такая цепочка может работать, но лишние переходы увеличивают время ответа и усложняют диагностику. Когда конечный адрес известен заранее, правило часто можно настроить так, чтобы HTTP-запрос сразу переходил на итоговый HTTPS-адрес и нужный домен.

Для GET-проверки с телом, которое не нужно показывать, применяйте -D - и -o /dev/null:

curl -sS -D - -o /dev/null -L https://example.com/old

В таком выводе будут видны заголовки каждого ответа, а содержимое страниц не попадет в терминал. Этот вариант удобен для скриптов и повторных проверок после изменения конфигурации.

Ограничить число переходов и обнаружить петлю

Лимит переходов защищает проверку от бесконечного обмена между двумя URL:

curl -IL --max-redirs 5 https://example.com/old
curl -v -L --max-redirs 5 https://example.com/old

Если URL повторяется, например /old ведет на /new, а /new снова ведет на /old, curl завершит запрос после установленного лимита и сообщит о превышении числа перенаправлений. Повторяющиеся значения Location показывают петлю напрямую.

Для детального просмотра запроса и ответа используйте:

curl --trace-ascii /dev/stderr -L --max-redirs 5 https://example.com/old

Трассировка показывает отправленный метод, Host, путь, полученный код и заголовки. В ней могут оказаться cookies, токены и другие чувствительные данные, поэтому не публикуйте такой вывод без очистки.

Частые циклы возникают при переключении HTTP и HTTPS, нормализации www, добавлении завершающего слеша и работе приложения за reverse proxy. Для поиска причины выпишите все пары исходный URL, код и Location, затем найдите правило, которое снова обрабатывает уже нормализованный адрес.

Проверить конечный URL без лишнего шума

Для проверки конечного кода, итогового адреса и числа переходов используйте форматированный вывод:

curl -Ls -o /dev/null -w '%{http_code} %{url_effective} %{num_redirects}' https://example.com/old

Пример результата:

200 https://example.com/new 1

Здесь конечный сервер вернул 200, curl прошел один редирект, а итоговым адресом стал https://example.com/new. В автоматической проверке сравнивайте каждое значение с ожидаемым.

Если нужно проверить только исходный ответ и увидеть URL следующего перехода, отключите -L и используйте %{redirect_url}:

curl -sS -o /dev/null -w '%{http_code} %{redirect_url}' https://example.com/old

Такой вызов удобен для проверки одного правила в shell-скрипте. Для полной цепочки добавляйте -L и %{num_redirects}.

Как проверить разные сценарии запроса

Один успешный вызов curl не доказывает, что правило работает для всех вариантов URL. Составьте небольшую тестовую матрицу и меняйте только один параметр запроса за раз: схему, Host, путь, параметры или метод.

HTTP и HTTPS

Проверьте оба протокола отдельно:

curl -I http://example.com/path
curl -I https://example.com/path

Для принудительного перехода на HTTPS ожидайте редирект на первом адресе и обычно ответ 200 на втором, если путь существует. Если HTTPS снова перенаправляет на HTTP или HTTP повторно возвращается на HTTPS, ищите конфликтующие правила и неверное определение исходной схемы.

При проверке конкретного сервера сохраните Host и SNI с помощью --resolve:

curl -I --resolve example.com:443:203.0.113.10 https://example.com/path

Здесь curl подключается к указанному IP, но отправляет имя example.com в Host и TLS SNI. Такой тест помогает отделить ответ нужного origin-сервера от ответа CDN, балансировщика или другого виртуального хоста.

За reverse proxy переменная $scheme показывает схему текущего соединения с Nginx. Если TLS завершился на балансировщике, Nginx может видеть внутренний HTTP и считать, что клиент пришел по HTTP. Правило, которое без проверки перенаправляет все такие запросы на HTTPS, создаст цикл.

Проверьте, какую схему передает прокси в X-Forwarded-Proto. Доверять этому заголовку можно только после настройки прокси, который сам переписывает его и не передает произвольное значение от клиента.

Основной домен, поддомен и server_name

Каждое имя из конфигурации нужно проверить отдельным запросом:

curl -I https://example.com/old
curl -I https://www.example.com/old
curl -I https://api.example.com/old

Правило может работать для example.com, но не срабатывать для www.example.com, если это имя отсутствует в server_name или попадает в другой блок. Аналогичная проблема возникает для поддоменов, IPv4 и IPv6.

Проверяйте фактический IP и виртуальный хост через --resolve:

curl -I --resolve www.example.com:443:203.0.113.10 https://www.example.com/old

Лишний default_server может перехватывать запросы с неизвестным Host. Отдельный listen [::]:80 нужен для IPv6, если сервер принимает такие соединения. Иначе IPv6-запрос может попасть в другой блок и вернуть код, который не совпадает с результатом IPv4-проверки.

Для отдельного тестового стенда можно использовать VDS или облачный сервер. Например, Timeweb Cloud предоставляет серверы и другую инфраструктуру для размещения тестовых конфигураций Nginx.

Путь, завершающий слеш и query-параметры

Сравните варианты пути, которые реально встречаются в запросах:

curl -I 'https://example.com/old'
curl -I 'https://example.com/old/'
curl -I 'https://example.com/old/item'
curl -I 'https://example.com/old?page=2&utm_source=test'

Путь /old и путь /old/ не идентичны для точного location. Вложенный адрес /old/item может попасть в префиксный или регулярный блок и обойти правило, которое рассчитано только на один URL.

Сравните query string в исходном и целевом адресе. Параметры могут сохраниться автоматически, исчезнуть из-за новой подстановки или продублироваться. Проверяйте отсутствие двойного вопросительного знака, двойного слеша, старого пути и неожиданного переноса параметров в другую часть URL.

Для явного сохранения параметров в целевом URI часто используют переменные $is_args и $args:

return 301 https://example.com/new$is_args$args;

Если параметры отсутствуют, $is_args не добавляет знак вопроса. Если параметры есть, результат содержит ?page=2 и другие значения из исходного запроса.

GET, HEAD и другие HTTP-методы

Сначала сопоставьте HEAD и GET:

curl -I https://example.com/old
curl -i https://example.com/old

curl -i уже отправляет GET, поэтому добавлять -X GET обычно не требуется. Если HEAD возвращает 301, а GET возвращает 200, проверьте обработчик приложения, прокси и ограничения для метода.

Для API и форм используйте безопасный тестовый endpoint и отдельно проверьте исходный метод:

curl -i -X POST --data 'name=test' https://example.com/api/old

Коды 307 и 308 должны сохранять метод и тело при переходе. При 301, 302 и 303 клиент может изменить POST на GET. Не отправляйте повторно боевые операции только ради проверки редиректа. Для тестов используйте staging, идемпотентный endpoint или заранее подготовленный запрос без побочных эффектов.

В таблице проверки фиксируйте исходный метод, код ответа, значение Location и конечный код. Наблюдаемый результат важнее предположения о том, какой блок конфигурации должен был сработать.

Как распознать типовую неисправность по выводу curl

Вывод curl дает достаточно признаков для первичной классификации проблемы. Сначала запишите код, Location, количество переходов и конечный URL, затем связывайте симптом с конкретным уровнем конфигурации.

Location указывает не на тот адрес

Проверьте каждую часть значения Location:

  • схема должна соответствовать требуемому HTTP или HTTPS-сценарию;
  • домен должен быть целевым, без случайного www или его отсутствия;
  • порт должен быть доступен клиенту и соответствовать публичному адресу;
  • путь не должен терять каталог, добавлять лишний слеш или повторять часть URI;
  • query string должна сохраняться, удаляться или изменяться согласно задаче.

Например, ответ location: https://example.com/new/old при ожидаемом https://example.com/new часто указывает на неправильную подстановку URI. Адрес с http:// вместо https:// требует проверки схемы и reverse proxy. Двойной слеш обычно появляется при склейке переменной с завершающим слешем.

Для точной фиксации результата используйте:

curl -sS -D - -o /dev/null https://example.com/old

Сравните полученный заголовок с ожидаемым адресом посимвольно. Такой подход быстро обнаруживает неправильный домен, порт, путь и параметры.

Редирект зациклился

Петля видна по повторяющимся URL или по двум правилам, которые возвращают запрос друг другу. Типовые пары выглядят так:

  • HTTP перенаправляется на HTTPS, а прокси снова сообщает Nginx, что исходная схема HTTP;
  • www.example.com перенаправляется на example.com, а другой server block возвращает клиента на www.example.com;
  • /path получает завершающий слеш, а правило для /path/ удаляет его;
  • правило для старого пути повторно срабатывает после подстановки нового URI.

Запустите проверку с ограничением переходов:

curl -IL --max-redirs 10 https://example.com/path

Выпишите последовательность вида URL -> код -> Location. Найдите первый повтор. Затем проверьте условие, которое должно исключать уже нормализованный URL: схему, Host, слеш или путь.

Вместо редиректа приходит 200, 404 или 500

РезультатВероятная причинаСледующий тест
200Запрос обработал статический файл, приложение или proxy_passПроверить server block, location и порядок выбора маршрута
403Запрещен доступ к каталогу, файлу или upstreamПроверить права, allow/deny и обработчик ресурса
404Путь попал в другой location или целевой ресурс отсутствуетСравнить точный URI, server_name и access log
500Ошибка приложения, rewrite или внутреннего обработчикаПроверить error log и конфигурацию upstream
502Nginx не получил корректный ответ от upstreamПроверить доступность backend и error log Nginx

Код 404 или 500 не доказывает ошибку именно в директиве rewrite. Сначала определите, какой обработчик сформировал ответ. Полезно сопоставить время запроса, Host и URI в access log с сообщением error log.

Редирект работает только для части URL

Сравните рабочий и нерабочий запросы, изменяя один признак:

  • регистр пути, например /Old и /old;
  • завершающий слеш;
  • вложенный URI;
  • наличие query string;
  • основной домен, www и поддомен;
  • IPv4 и IPv6;
  • прямой запрос к origin и запрос через CDN или балансировщик;
  • HEAD, GET и допустимый метод API.

Точный location = /old обрабатывает только один URI. Префиксный блок location /old охватывает больше адресов, а регулярное выражение может перехватывать запросы в зависимости от порядка блоков. Флаг ^~ меняет участие регулярных location в выборе обработчика. Проверяйте фактический маршрут через логи, а не по названию блока в файле.

Какие ошибки конфигурации Nginx мешают редиректу

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

Ошибки в return и rewrite

Для простого перенаправления обычно достаточно return:

server {
    listen 80;
    server_name old.example.com;
    return 301 https://new.example.com$request_uri;
}

Директива return сразу завершает обработку запроса и возвращает указанный код. Готовые варианты для переноса сайта, каталога и отдельных страниц через return приведены в статье о настройке редиректов в Nginx без rewrite.

rewrite полезен, когда путь нужно преобразовать по шаблону:

server {
    listen 80;
    server_name example.com;
    rewrite ^/old/?$ /new permanent;
}

Флаг permanent возвращает 301. Флаг redirect возвращает 302. Ошибка в регулярном выражении может расширить охват правила или исключить нужный URI. Якорь ^ ограничивает начало пути, а $ его конец. Без якорей правило для /old может затронуть /old-stock и другие адреса.

Проверяйте соответствие кода задаче. 301 и 308 закрепляют постоянный перенос, 302 и 307 подходят для временных сценариев. Для метода-зависимых запросов выбирайте код, который сохраняет метод, и проверяйте его через POST или другой допустимый метод.

При сборке целевого URL не смешивайте переменные с лишними слешами. Для сохранения исходного пути используйте $request_uri, а для явной работы с параметрами применяйте $is_args$args. После каждой правки проверяйте адреса без параметров и с параметрами.

Неверный server block или location

Если правило выглядит корректно, но curl получает 200, 404 или неожиданный Location, запрос может обслуживать другой блок. Выведите полную загруженную конфигурацию:

sudo nginx -T

Проверьте директивы listen, server_name, default_server и наличие отдельного блока для IPv6. Сопоставьте их с адресом, портом и Host, которые использует curl.

Затем проверьте выбор location. Точный блок с =, самый длинный префикс и регулярные выражения могут привести запрос в разные обработчики. Прокси, alias, обработка статического файла или приложение могут сформировать ответ раньше, чем сработает ожидаемое правило.

Для проверки конкретного блока используйте отдельные Host и IP:

curl -I --resolve example.com:443:203.0.113.10 https://example.com/old
curl -i -H 'Host: example.com' http://203.0.113.10/old

Второй запрос полезен для HTTP-origin, но не заменяет проверку TLS с корректным SNI. Для HTTPS используйте --resolve, чтобы имя сохранялось на уровнях HTTP и TLS.

Проблемы с HTTPS за reverse proxy или CDN

При нескольких уровнях проксирования нужно разделить три значения: схема клиента, схема соединения между прокси и Nginx, схема соединения Nginx с upstream. Переменная $scheme отражает текущий входящий запрос, а не обязательно исходный протокол пользователя.

Петля возникает по такой схеме:

  1. клиент открывает HTTPS-адрес;
  2. CDN завершает TLS и отправляет HTTP на Nginx;
  3. Nginx видит $scheme=http и возвращает редирект на HTTPS;
  4. CDN снова подключается к Nginx по HTTP.

Проверьте, передает ли доверенный прокси X-Forwarded-Proto: https, и настроено ли условие, которое использует это значение. Сам клиент не должен иметь возможность произвольно задавать доверенный заголовок, поэтому прокси должен его перезаписывать.

Сравните публичный и прямой запрос к origin. Для публичного адреса используйте обычный curl, для origin сохраните Host и SNI через --resolve. Разница в кодах или Location покажет, на каком уровне появляется перенаправление.

Логи Nginx как подтверждение причины

Access log подтверждает, какой Host, URI, код и upstream status увидел сервер. Error log показывает ошибки синтаксиса, rewrite, proxy и подключения к backend.

sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log

Для глубокой диагностики маршрутизации используйте пошаговое руководство по логированию и проверке location в Nginx. Оно помогает связать ответ curl с фактически выбранным маршрутом и upstream.

Если стандартного access log недостаточно, временно добавьте поля Host, URI, код, отправленный Location и upstream status:

log_format redirect_debug '$remote_addr host=$host request=$request status=$status location=$sent_http_location upstream_status=$upstream_status scheme=$scheme';

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

Безопасная последовательность применения изменений:

sudo nginx -t
sudo nginx -s reload

Вместо сигнала nginx -s reload можно использовать sudo systemctl reload nginx, если сервис управляется systemd. Подробнее о проверке конфигурации, graceful reload и откате описано в руководстве по безопасному обновлению конфигурации Nginx.

Итоговый чек-лист проверки редиректа

Минимальный набор команд

После настройки или изменения правила выполните команды в таком порядке:

  1. Проверьте синтаксис: sudo nginx -t.
  2. Примените конфигурацию: sudo nginx -s reload или sudo systemctl reload nginx.
  3. Проверьте исходные заголовки: curl -I https://example.com/old.
  4. Сравните GET с HEAD: curl -sS -D - -o /dev/null https://example.com/old.
  5. Посмотрите всю цепочку: curl -IL --max-redirs 10 https://example.com/old.
  6. Получите конечный код и URL: curl -Ls -o /dev/null -w '%{http_code} %{url_effective} %{num_redirects}' https://example.com/old.
  7. При проблеме включите подробный вывод: curl -v -L --max-redirs 5 https://example.com/old.
  8. Проверьте нужный IP и виртуальный хост: curl -I --resolve example.com:443:203.0.113.10 https://example.com/old.
  9. Сопоставьте запрос с access log и error log.

Что считать проверкой, завершенной успешно

  • исходный URL получает ожидаемый код 301, 302, 307 или 308;
  • Location содержит правильные схему, домен, порт, путь и параметры;
  • цепочка не содержит циклов и лишних переходов;
  • конечный URL возвращает ожидаемый код, например 200 для доступной страницы;
  • проверены HTTP и HTTPS, основной домен, www, поддомены и нужные порты;
  • проверены варианты со слешем, вложенными путями и query string;
  • для API и форм проверен исходный HTTP-метод;
  • конфигурация прошла nginx -t и загружена через reload;
  • при расхождении результат подтвержден access log и error log.

Главные признаки исправной настройки просты: код соответствует задаче, Location ведет точно к нужному адресу, цепочка короткая, петля отсутствует, а конечный ответ ожидаем. Повторяйте эту проверку после каждой правки return, rewrite, server_name, location или схемы работы reverse proxy.

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