Маршрутизация нескольких адресов сайта к одному каноническому URL через Nginx
DevOps

Редиректы и канонический адрес сайта в Nginx

Настраиваем HTTP→HTTPS, www и перенос URL в Nginx без циклов и потери пути: return, проверка Location, временные и постоянные коды.

Содержание

Одна страница может открываться по http://example.com, https://example.com и https://www.example.com. Если все варианты отдают содержимое, поисковая система и внешние ссылки видят несколько адресов одного материала. Выберите один канонический вариант, а остальные направьте к нему за один переход.

В примерах основным будет https://example.com. Сначала настроим временный редирект и проверим заголовок Location, путь и параметры. Постоянный код следует включать после проверки: браузеры и поисковые роботы могут надолго запомнить ошибочный адрес.

Выберите канонический вариант

До конфигурации зафиксируйте решение:

  • HTTPS обязателен для основного сайта;
  • используется домен с www или без него;
  • сохраняются ли путь и query string;
  • какие старые URL должны вести на новые;
  • где заканчивается TLS — на этом Nginx или на внешнем proxy.

DNS каждого исходного имени должен вести в вашу инфраструктуру, а TLS-сертификат — покрывать имена, которые принимают HTTPS. Редирект не исправляет отсутствующий сертификат: браузер устанавливает TLS до получения HTTP-ответа.

Перенаправьте HTTP на HTTPS

Оба HTTP-варианта можно принять одним блоком и сразу направить на окончательный HTTPS-адрес. Директива return формирует ответ 302 и заголовок Location без обработки файлов сайта:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    return 302 https://example.com$request_uri;
}

$request_uri сохраняет исходный путь и аргументы. Начните с 302, проверьте все варианты и только затем замените на выбранный постоянный код. Для большинства обычных GET-страниц применяется 301. Коды 307/308 сохраняют метод и тело запроса, что важно для API, но перенос POST-запросов нужно проектировать отдельно, а не полагаться только на код.

Окончательный HTTPS-блок не перенаправляет запрос, а обслуживает содержимое. Он должен иметь сертификат для example.com и каталог опубликованного сайта:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    root /var/www/example/current;
    index index.html;
}

Пути сертификата — пример структуры ACME-клиента. Используйте фактические файлы и не копируйте приватный ключ в репозиторий.

Отдельно обработайте HTTPS на www

Чтобы https://www.example.com смог вернуть редирект, Nginx должен успешно завершить TLS с сертификатом, включающим www:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name www.example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    return 302 https://example.com$request_uri;
}

После теста измените временный код. Не отправляйте все неизвестные хосты на $host: входной заголовок контролирует клиент. Для default server безопаснее отдельный отказ, если у проекта нет осознанной причины обслуживать посторонние имена.

Когда нужен rewrite

rewrite полезен для преобразования структуры пути, например строго известного старого раздела:

location /old-docs/ {
    rewrite ^/old-docs/(.*)$ /docs/$1 permanent;
}

Если переносится одна страница без изменения остальных адресов, регулярное выражение не требуется. Точное location = с return явно связывает старый и новый путь:

location = /old-page {
    return 302 /new-page;
}

Составьте таблицу старый → новый адрес. Массовое правило с (.*) может отправить разные материалы на нерелевантную страницу и скрыть настоящие 404. Для SEO ценен точный перенос смысла, а не сам факт редиректа.

Не создавайте цепочки и циклы

Плохая цепочка делает два перехода: http://wwwhttps://wwwhttps://без-www. Сразу направляйте каждый контролируемый вариант на финальный адрес.

За внешним балансировщиком внутренний Nginx может видеть HTTP. Если он принимает решение только по $scheme, получится цикл. Настройте внешний proxy, доверенные адреса и передачу исходного протокола как единую схему. Не доверяйте X-Forwarded-Proto от любого клиента.

Проверьте все исходные адреса

Сначала проверьте конфигурацию и примените её через reload. Затем запросите каждый исходный вариант без загрузки тела, а в последней команде попросите curl пройти всю цепочку не более чем за пять переходов:

sudo nginx -t
sudo systemctl reload nginx
curl -I http://example.com/docs/?ref=test
curl -I http://www.example.com/docs/?ref=test
curl -I https://www.example.com/docs/?ref=test
curl -IL --max-redirs 5 http://www.example.com/docs/?ref=test

Проверьте один переход, правильный Location, сохранение пути и отсутствие неожиданного переноса query. Затем проверьте реальную страницу на конечном адресе. Браузерный кеш не заменяет curl с видимыми заголовками.

Если тест не прошёл, верните сохранённый конфиг, выполните nginx -t и reload. Принципы структуры конфигурации разобраны в отдельном уроке, а выпуск HTTPS — в материале про домен, Nginx и HTTPS.

Контроль после публикации

Редиректы нужно проверить не только сразу после reload. Просмотрите access log через несколько часов: старые адреса не должны давать неожиданные 404 или повторяться цепочкой. Обновите canonical и внутренние ссылки в самом сайте, sitemap и внешних настройках — редирект страхует старые переходы, но не заменяет правильные конечные URL.

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

Первоисточники

Рекламное местоВаша компания здесьРазместить рекламу

Самопроверка

Проверьте, что материал усвоен

Ответьте на все вопросы. Результат сохранится только в этом браузере и будет учтён в статистике прочитанных материалов.

01Что предпочтительнее для простого переноса всего хоста?
02Почему постоянный редирект лучше включать после временного теста?
03Что обязательно проверить после изменения?

Разбираем коротко

Частые вопросы

Какой код использовать для проверки нового редиректа?

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

Сохраняет ли return 301 https://example.com$request_uri параметры запроса?

Да, переменная request_uri содержит исходный путь вместе с аргументами. Это удобно для перенаправления HTTP на HTTPS, если именно такое сохранение соответствует требуемой логике.

Почему возникает бесконечный цикл редиректов за reverse proxy?

Nginx может видеть внутреннее HTTP-соединение и снова отправлять клиента на HTTPS, хотя внешний прокси уже завершил TLS. Нужно согласовать доверенный заголовок протокола и правила между всеми прокси, а не отключать редирект случайным условием.