Перенаправление HTTP на HTTPS в Nginx: лучшие практики

Настройте надежное перенаправление с HTTP на HTTPS в Nginx с помощью выделенного блока порта 80, избегайте циклов перенаправления, выбирайте правильный код перенаправления и добавляйте HSTS, когда будете готовы.

Перенаправление HTTP на HTTPS в Nginx: лучшие практики

Перенаправление HTTP на HTTPS в Nginx гарантирует, что посетители используют зашифрованную версию вашего сайта, даже если они вводят старый URL http:// или переходят по устаревшей ссылке. Чистая настройка перенаправления повышает безопасность, избегает дублирования URL и предоставляет пользователям единую точку входа.

Лучший подход обычно прост: держите порт 80 открытым только для перенаправления трафика, а реальный сайт обслуживайте на порту 443 с действительным TLS-сертификатом.

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

Воспринимайте перенаправление как часть вашего публичного API. Люди вставляют ссылки в чаты, поисковые системы их сканируют, системы мониторинга обращаются к ним, а старые письма хранят их годами. Если перенаправление стабильно, никто не замечает. Если оно небрежное, пользователи видят предупреждения о сертификатах, сломанные пути или ошибки слишком большого количества перенаправлений, прежде чем ваше приложение вообще получит запрос.

Почему важны перенаправления HTTPS

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

Перенаправления также помогают с согласованностью. Поисковые системы и пользователи не должны видеть http://example.com/page и https://example.com/page как два разных адреса. Постоянное перенаправление сообщает клиентам, что HTTPS является предпочтительной версией.

Стандартный шаблон Nginx — это выделенный серверный блок на порту 80:

server {
    listen 80;
    server_name example.com www.example.com;

    return 301 https://$host$request_uri;
}

Затем ваш HTTPS-серверный блок обрабатывает реальный сайт:

server {
    listen 443 ssl http2;
    server_name example.com www.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.com;
    index index.html;
}

Директива return 301 эффективна и понятна. Она указывает Nginx отправить постоянное перенаправление без дополнительной обработки location. $request_uri сохраняет путь и строку запроса, поэтому /docs?page=2 становится https://example.com/docs?page=2.

Для полной настройки TLS см. обеспечение безопасности Nginx с HTTPS.

Для большинства сайтов избегайте размещения логики приложения в блоке порта 80. Он не должен обслуживать статические файлы, проксировать на приложение или содержать большой набор location. Держите его простым:

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

Этот маленький блок легче проверять и он менее склонен к расхождению с HTTPS-конфигурацией.

Выбор между перенаправлениями 301 и 302

Используйте 301 для постоянного перенаправления HTTP на HTTPS на рабочем сайте. Браузеры и поисковые системы понимают, что HTTPS URL должен заменить HTTP URL.

Используйте 302 или 307 только когда перенаправление временное. Например, вы можете использовать временное перенаправление во время тестирования, пока сертификаты и имена хостов не окончательны. Когда HTTPS сайт будет готов, переключитесь на постоянное перенаправление.

Будьте осторожны на ранних этапах настройки. Браузеры могут агрессивно кэшировать перенаправления 301. Если вы случайно перенаправите на неправильное имя хоста, браузер может продолжать использовать неверное перенаправление даже после исправления Nginx. По возможности тестируйте с помощью curl, приватных окон браузера и нерабочих имен хостов.

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

  1. Убедитесь, что HTTPS серверный блок работает напрямую.
  2. Убедитесь, что сертификат соответствует каждому имени хоста.
  3. Добавьте серверный блок перенаправления HTTP.
  4. Протестируйте несколько путей и строк запроса.
  5. Изменяйте временные перенаправления на постоянные только когда поведение корректно.

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

Например, чтобы перенаправить весь HTTP трафик на HTTPS имя хоста без www:

server {
    listen 80;
    server_name example.com www.example.com;

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

Это отличается от https://$host$request_uri, который сохраняет то имя хоста, которое запросил пользователь.

Вы также можете разделить перенаправления имени хоста и схемы, если хотите, чтобы поведение было явным:

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

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

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

Избегание циклов перенаправления и проблем с сертификатами

Циклы перенаправления возникают, когда Nginx, балансировщик нагрузки или приложение продолжают отправлять запрос обратно на URL, который запускает другое перенаправление. Это распространено, когда TLS завершается до Nginx, например, в облачном балансировщике нагрузки или CDN.

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

Исправление зависит от вашей архитектуры. Обычно балансировщик нагрузки должен передавать заголовки, такие как X-Forwarded-Proto, а приложение или конфигурация Nginx должны доверять им только от известных адресов прокси.

Например, если Nginx находится за доверенным балансировщиком нагрузки и получает только внутренний HTTP, вы, возможно, не захотите, чтобы Nginx перенаправлял каждый локальный HTTP запрос. Вместо этого балансировщик нагрузки может обрабатывать публичное перенаправление HTTP на HTTPS, в то время как Nginx обслуживает трафик из частной сети. Если Nginx должен принимать решение, ему нужна надежная информация о пересылаемом протоколе от прокси перед ним. Не доверяйте X-Forwarded-Proto от произвольных интернет-клиентов.

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

Тестируйте с помощью:

curl -I http://example.com/some/path?x=1

Ищите:

HTTP/1.1 301 Moved Permanently
Location: https://example.com/some/path?x=1

Затем протестируйте HTTPS URL:

curl -I https://example.com/some/path?x=1

HTTPS ответ должен возвращать фактический статус страницы, а не другое перенаправление обратно на HTTP.

Также протестируйте оба имени хоста, если оба существуют:

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

Вы ищете короткую, предсказуемую цепочку. Одно перенаправление с HTTP на канонический HTTPS URL — это хорошо. Множественные переходы, такие как HTTP без www на HTTPS без www на HTTPS с www и обратно, являются признаком того, что Nginx, приложение, правила CDN или перенаправление на уровне DNS конфликтуют друг с другом.

Вы можете проверить всю цепочку с помощью:

curl -IL http://www.example.com/some/path

Флаг -L следует за перенаправлениями. В чистой настройке вывод должен показывать начальный HTTP ответ, а затем финальный HTTPS ответ. Если вы видите три или четыре заголовка Location, упростите правила, пока не останется один четкий маршрут к каноническому URL.

HSTS и другие лучшие практики

После того, как ваша HTTPS настройка стабильна, вы можете рассмотреть HTTP Strict Transport Security, обычно называемый HSTS. HSTS сообщает браузерам автоматически использовать HTTPS для будущих посещений.

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

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

Не добавляйте это легкомысленно. Если вы включаете поддомены, каждый поддомен должен поддерживать HTTPS. Если вы позже сломаете HTTPS, браузеры, которые видели заголовок HSTS, могут отказаться доступаться к HTTP версии. Начните с более короткого max-age во время тестирования, затем увеличьте его, когда будете уверены.

Другие лучшие практики:

  • Держите блок порта 80 простым.
  • Сохраняйте пути и строки запроса, если у вас нет причины не делать этого.
  • Выберите одно каноническое имя хоста.
  • Тестируйте перенаправления с помощью curl, а не только браузера.
  • Обновляйте сертификаты автоматически и отслеживайте сбои обновления.
  • По возможности держите логику перенаправления в Nginx, а не дублируйте ее в приложении.

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

Распространенные ошибки

Самая распространенная ошибка — использование rewrite для простого перенаправления:

rewrite ^ https://example.com$request_uri permanent;

Это может работать, но return 301 ... понятнее и избегает лишней обработки rewrite. Используйте rewrite, когда вам действительно нужно сопоставление с образцом, а не для базового перенаправления схемы.

Другая ошибка — перенаправление на $server_name без понимания того, что он содержит. $host берется из заголовка хоста запроса, в то время как $server_name основан на сопоставленном имени сервера Nginx. Для канонических перенаправлений буквальное имя хоста часто является наименее удивительным вариантом:

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

Вам также следует избегать перенаправления путей ACME HTTP challenge, если ваш инструмент сертификатов нуждается в них на порту 80. Многие настройки Let's Encrypt обрабатывают это автоматически, но пользовательские конфигурации могут нуждаться в исключении:

location /.well-known/acme-challenge/ {
    root /var/www/letsencrypt;
}

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

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

Безопасный шаблон развертывания

Для рабочего сайта вносите изменения поэтапно:

  1. Убедитесь, что HTTPS серверный блок правильно обслуживает сайт.
  2. Убедитесь, что обновление сертификата работает или отслеживается.
  3. Добавьте временное перенаправление на порту 80, если вы все еще тестируете имена хостов.
  4. Протестируйте общие URL с помощью curl -I и curl -IL.
  5. Переключитесь на 301, когда цель перенаправления окончательна.
  6. Подождите перед включением долгоживущего HSTS.

Этот период ожидания полезен. Он дает вам время обнаружить забытые поддомены, старые URL вебхуков, жестко закодированные ссылки http:// или правило CDN, которое не было видно с вашей первой тестовой машины.

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

Пример: статический сайт и обратный прокси

Для статического сайта HTTPS блок может содержать только корень документов:

server {
    listen 443 ssl http2;
    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.com;
    index index.html;
}

Для приложения за Nginx блок перенаправления остается тем же, но HTTPS блок проксирует трафик:

server {
    listen 443 ssl http2;
    server_name example.com;

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

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Важный момент — разделение. Порт 80 решает, куда браузер должен идти. Порт 443 обслуживает сайт. Смешивание этих задач усложняет анализ поведения перенаправления, особенно когда позже добавляется другой прокси или CDN.

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

sudo nginx -t
sudo systemctl reload nginx

Если тест не удался, не перезагружайте. Сначала исправьте синтаксическую ошибку, затем протестируйте снова.

Одну финальную проверку стоит выполнить извне сервера, а не только по SSH на хосте. Брандмауэр, CDN или балансировщик нагрузки могут изменить то, что видят реальные пользователи. Выполните те же проверки curl -I с вашего ноутбука, из места мониторинга или временного облачного экземпляра. Если внешний результат отличается от localhost, проблема с перенаправлением, вероятно, в сетевом уровне перед Nginx, а не в самом серверном блоке. Проверьте это, прежде чем переписывать рабочую конфигурацию.

Когда обращаться за помощью

Обратитесь за помощью к DevOps инженеру, если ваш сайт находится за CDN, облачным балансировщиком нагрузки, Kubernetes ingress или несколькими обратными прокси. Перенаправления HTTPS в многоуровневой инфраструктуре зависят от того, где завершается TLS и каким заголовкам доверяют.

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

Перенаправление HTTP на HTTPS в Nginx — это небольшое изменение конфигурации с большим влиянием на безопасность. Используйте выделенный блок перенаправления на порту 80, сохраняйте URI запроса, проверяйте сертификаты и тестируйте на наличие циклов, прежде чем считать задачу выполненной.