Блог

301-редирект в Nginx: домен, HTTPS, путь и параметры

Отдельный исходный домен принимает HTTP и HTTPS и одним ответом отправляет посетителя на www. Nginx сохраняет исходный путь и параметры; Certbot обслуживает сертификат источника.

Что понадобится

Пример маршрута
Исходный URLhttps://example.com/docs/start?tag=a&tag=b
HTTP301
Назначениеhttps://www.example.com/docs/start?tag=a&tag=b

Фиксированное назначение. Меняется хост; путь и повторяющиеся параметры остаются.

Этот способ подходит, если Nginx и Certbot уже установлены, а вы можете менять конфигурацию и перезагружать сервер. Нужны права на DNS исходного домена, доступность портов 80 и 443 и рабочий сайт на www.

Найдите действующий блок с server_name example.com. Если он уже существует, правьте его, а не добавляйте конкурирующий vhost. Сохраните копию конфигурации. Каталоги вроде /etc/nginx/conf.d/ — распространённый пример, но включаемые файлы определяются вашей установкой.

Все адреса example.com и example.org здесь демонстрационные. Замените их своими. Меняйте только исходный хост: рабочие DNS-записи назначения должны остаться на месте. Источник и назначение не должны перенаправлять друг на друга.

Для проверки нового правила можно сначала выбрать 302. После подтверждённого постоянного переезда переключите его на 301: браузер способен кешировать постоянный редирект, и откат серверной настройки не удаляет уже сохранённый ответ у посетителя.

1. Сначала настройте HTTP и ACME

Направьте A-запись источника на ваш Nginx. Если опубликована AAAA-запись, IPv6 тоже должен вести на доступный сервер: забытая запись может ломать выдачу сертификата и часть переходов. Записи www не переносите.

На первом этапе добавьте только блок порта 80. Исключение для ACME отдаёт проверочный файл, остальные запросы получают редирект.

Nginx · исходный HTTP-хост
server {
    listen 80;
    server_name example.com;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/letsencrypt;
    }
    location / {
        return 301 https://www.example.com$request_uri;
    }
}

Не переносите return на уровень этого server: такой ответ сработает до обработки нужного location и помешает webroot-проверке. Убедитесь, что Nginx может читать каталог challenge.

Создать webroot, проверить и применить конфигурацию
sudo mkdir -p /var/www/letsencrypt
sudo nginx -t
sudo nginx -s reload

Перезагружайте только после успешного nginx -t. Для установки с другими путями или способом управления используйте её штатную команду reload. При опубликованном IPv6 настройте и соответствующий IPv6-listener.

2. Выпустите сертификат, затем включите 443

Выдача сертификата источника
sudo certbot certonly --webroot -w /var/www/letsencrypt -d example.com

Дождитесь успешной выдачи. Только после этого добавляйте HTTPS-блок, ссылающийся на файлы сертификата. Иначе проверка Nginx завершится ошибкой из-за отсутствующих файлов.

Nginx · исходный HTTPS-хост
server {
    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;

    return 301 https://www.example.com$request_uri;
}

Пути в примере типовые. Используйте фактические пути, которые сообщил Certbot: имя lineage может отличаться. В общей TLS-конфигурации сохраните принятые для вашего сервера параметры. После изменения снова выполните sudo nginx -t и затем sudo nginx -s reload.

Переменная $request_uri включает исходный URI с query. Подстановка только $uri не равнозначна ей: она не переносит строку параметров и отражает нормализованный путь. Домен назначения задан явно, а не собирается из входящего Host.

3. Проверьте продление и загрузку сертификата

Проверьте, что для вашей установки Certbot включён штатный timer или cron; второй дублирующий планировщик не нужен. Webroot и исключение /.well-known/acme-challenge/ должны оставаться доступными и после запуска редиректа.

Команда certonly не означает, что Nginx сам перечитает обновлённые файлы. Настройте deploy hook, который после успешного продления проверит конфигурацию и выполнит reload. При стандартном каталоге Certbot это может быть исполняемый файл /etc/letsencrypt/renewal-hooks/deploy/reload-nginx:

Содержимое deploy hook
#!/bin/sh
set -eu
nginx -t
nginx -s reload

Используйте доступные hook-процессу пути к бинарнику. Проверку выпуска и продления выполните командой ниже; запуск deploy hook при dry-run зависит от параметров Certbot, поэтому отдельно убедитесь, что он исполняется в вашем режиме обслуживания.

Проверка продления
sudo certbot renew --dry-run

Nginx отвечает за TLS исходного example.com. Сертификат www остаётся у хостинга назначения, даже когда оба имени принадлежат вам.

4. Проверьте статус и Location

Проверка корня и вложенного URL · GET
curl -sS -o /dev/null -D - 'http://example.com/'
curl -sS -o /dev/null -D - 'http://example.com/docs/start?tag=a&tag=b&utm_source=mail'
curl -sS -o /dev/null -D - 'https://example.com/'
curl -sS -o /dev/null -D - 'https://example.com/docs/start?tag=a&tag=b&utm_source=mail'

Ожидайте код 301. Для корня заголовок Location должен быть https://www.example.com/, для вложенного адреса — https://www.example.com/docs/start?tag=a&tag=b&utm_source=mail. Версия HTTP и регистр имени заголовка в выводе могут отличаться. Если временно выбрали 302, ожидаемый код — 302.

Дополнительно: HEAD и закодированные символы
curl -sS -I 'https://example.com/docs/start?tag=a&tag=b'
curl --path-as-is -sS -o /dev/null -D - 'https://example.com/files/report%20one.pdf?tag=a&tag=b&q=a%2Fb'

Не добавляйте -L к первой проверке: важно увидеть ответ источника, а не скрыть его за переходом. Затем отдельно откройте адрес назначения и убедитесь, что там есть нужная страница. DNS не создаёт HTTP-ответ, а сертификат назначения не заменяет сертификат источника.

Для этого правила и HTTP, и HTTPS должны сразу вести на HTTPS-назначение. Исключение — путь ACME: он намеренно обслуживается локально. Проверьте также закодированный слеш %2F на своей целевой системе, не только обычный путь.

Если результат отличается

Симптом → проверка
СимптомЧто проверить
nginx -t сообщает об отсутствующем сертификатеВыдача не завершена или указан чужой путь lineage. Верните HTTP-этап, проверьте пути, затем добавьте 443.
Certbot не проходит challengeA/AAAA, порт 80, доступ к webroot и отсутствие server-level return перед ACME-location.
Путь есть, параметры исчезлиИспользуется ли $request_uri целиком; не обрезает ли их следующий редирект на целевом сайте.
После правки браузер идёт по-старомуСравните свежий ответ curl с браузером: сохранённый 301 может обходить сервер.

Для отката восстановите сохранённый блок источника, выполните configtest и reload. Если меняли DNS, возвращайте его только на готовый прежний обработчик. Не удаляйте сертификат, пока HTTPS-источник ещё используется.

Что остаётся обслуживать

Вы сохраняете сервер, обновления Nginx и ОС, DNS, регистрацию домена, планировщик Certbot и reload после продления. На уже оплаченном сервере отдельного счёта за этот vhost может не быть. Выбор управляемого сервиса — прежде всего отказ от этой обязанности, а не гарантированная экономия на любом хостинге.

Этот рецепт переводит весь исходный хост. Если на нём должен оставаться живой сайт, сначала определите отдельные правила в его конфигурации; не заменяйте весь vhost таким примером.

Документация

Нужен редирект, а не ещё одна настройка?

На существующем Nginx редирект может не добавлять расходов на хостинг. Redirect301 — вариант, если вы хотите передать обслуживание сервера, правил и сертификата источника.

Redirect301 — 500 ₽ за домен в год. Мы берём на себя правила перенаправления, HTTPS и продление сертификата исходного домена. Подключение через DNS охватывает весь исходный хост; для отдельных страниц живого сайта нужна отдельная интеграция.

Что входит в 500 ₽

Redirect301

Узнать о запуске Redirect301

Оставьте email, чтобы получить уведомление об открытии доступа.