Настройка HTTPS-редиректов и HSTS — одна из тех задач, которая выглядит простой на бумаге, но на практике регулярно ломает сайты, портит SEO и создаёт дыры в безопасности. За 10 лет работы я разгребал последствия неправильных редиректов не один десяток раз — и всякий раз убеждался, что дьявол в деталях.
Почему это всё ещё актуально в 2026 году
Казалось бы, HTTPS уже давно стал стандартом. Chrome с 2018 года показывает «Небезопасно» для HTTP-сайтов, Let's Encrypt раздаёт бесплатные сертификаты, хостинги научились выдавать SSL в один клик. Но проблемы не исчезли — они просто стали другими.
На прошлой неделе ко мне обратился клиент с интернет-магазином на Битриксе. Сертификат есть, HTTPS работает, но Google Search Console показывает тысячи смешанных URL — часть страниц индексируется как HTTP, часть как HTTPS. Результат: позиции упали, PageSpeed на мобильных просел до 34 баллов, а в консоли браузера — постоянные предупреждения о mixed content. Причина оказалась банальной: редиректы настроены на уровне CMS, но не на уровне сервера, и часть запросов проскакивала мимо.
Или другой случай — клиент настроил HSTS с директивой includeSubDomains, не проверив, что на поддомене old.site.ru живёт HTTP-версия тестового сервера без сертификата. После добавления в preload-список браузеры намертво заблокировали весь трафик на поддомен, а откатиться было уже нельзя — HSTS preload list обновляется месяцами. Пришлось экстренно выпускать сертификат и поднимать HTTPS на тестовом сервере.
Если вас интересует базовая теория, я рекомендую сначала прочитать статью про SSL-сертификаты — там подробно разобрано, как работает TLS и зачем он нужен. А здесь я буду говорить именно о практической настройке редиректов и HSTS.
Как работает HTTPS-редирект: механика и уровни
Редирект с HTTP на HTTPS — это ответ сервера с кодом 301 (постоянный) или 302 (временный). Для SEO и безопасности нужен именно 301. Браузер получает этот ответ, запоминает новый адрес и больше не обращается по старому (в теории). На деле — первый запрос всегда идёт по HTTP, и это окно уязвимости, которое закрывает как раз HSTS.
Редиректы можно настроить на нескольких уровнях, и это важно понимать:
- Уровень веб-сервера (Nginx, Apache) — самый правильный вариант. Отрабатывает до того, как PHP вообще запустится. Быстро, надёжно, не зависит от CMS.
- Уровень .htaccess — для Apache, если нет доступа к основному конфигу. Чуть медленнее, но приемлемо.
- Уровень CMS (WordPress, Битрикс) — плохая идея для основного редиректа. CMS грузится, PHP выполняется, и только потом происходит редирект. Лишняя нагрузка и потенциальные баги.
- Уровень PHP-кода — ещё хуже. Забудьте про это как про основной механизм.
Грубо говоря, правило такое: чем ниже уровень редиректа — тем хуже. Всегда старайтесь выносить это на уровень Nginx или Apache.
Настройка редиректа в Nginx
Nginx — мой основной инструмент на большинстве серверных проектов. Вот правильная конфигурация для перенаправления HTTP → HTTPS:
server {
listen 80;
listen [::]:80;
server_name example.ru www.example.ru;
# Редирект всего трафика на HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.ru www.example.ru;
ssl_certificate /etc/letsencrypt/live/example.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.ru/privkey.pem;
# Современные настройки TLS
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# HSTS — подробнее об этом ниже
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Редирект www → без www (или наоборот, по вашему выбору)
if ($host = www.example.ru) {
return 301 https://example.ru$request_uri;
}
root /var/www/example.ru/public;
index index.php index.html;
# ... остальная конфигурация
}
Несколько моментов, на которые обращаю внимание. Во-первых, я использую return 301 вместо rewrite — это быстрее и семантически правильнее. Во-вторых, $host вместо $server_name — это важно, если у вас несколько доменов на одном сервере. В-третьих, http2 прямо в listen — с Nginx 1.25+ рекомендуют использовать отдельную директиву http2 on, но старый синтаксис пока работает.
После изменений не забывайте проверять конфиг и перезагружать Nginx:
nginx -t && systemctl reload nginx
Настройка редиректа в Apache и .htaccess
Apache встречается реже на современных серверах, но на шаред-хостингах — до сих пор норма. И там обычно только .htaccess без доступа к основному конфигу. Вот рабочий вариант:
RewriteEngine On
# Редирект HTTP → HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
# Редирект www → без www (опционально)
RewriteCond %{HTTPS} on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]
# HSTS через Header
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Обратите внимание: HSTS-заголовок через .htaccess работает только если включён модуль mod_headers. На большинстве хостингов он есть, но лучше проверить. Также важно, что директива Header always set — именно always, а не просто set. Без always заголовок не будет отправляться с 3xx и 4xx ответами.
Ещё один нюанс для WordPress: если у вас уже стоит файл .htaccess от WordPress с блоком # BEGIN WordPress, вставляйте правила редиректа до этого блока. Иначе WordPress rewrite rules могут перехватить запрос раньше.
Что такое HSTS и почему его недостаточно просто включить
HSTS (HTTP Strict Transport Security) — это HTTP-заголовок, который говорит браузеру: «Этот сайт всегда работает по HTTPS, больше не пробуй HTTP». Браузер запоминает это на время, указанное в max-age, и все последующие запросы автоматически переводит на HTTPS ещё до отправки — без дополнительного round-trip к серверу. Это закрывает атаки типа SSL-stripping.
Выглядит заголовок так:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Разберём каждую часть:
max-age=31536000— время в секундах (1 год). Браузер будет помнить это правило 365 дней.includeSubDomains— распространить правило на все поддомены. Вот здесь и живёт главная опасность.preload— разрешение на добавление домена в браузерный preload-список.
HSTS preload — отдельная история. Это статический список доменов, который зашит прямо в браузер (Chrome, Firefox, Safari, Edge). Даже если пользователь никогда не посещал ваш сайт, браузер уже знает, что он работает только по HTTPS. Список ведёт Google, добавить домен можно на hstspreload.org.
Я рекомендую такую стратегию внедрения HSTS:
- Сначала запустите без HSTS вообще — просто HTTPS-редирект. Убедитесь, что всё работает.
- Добавьте HSTS с маленьким
max-age=300(5 минут). Проверьте в браузере, что нет проблем. - Увеличьте до
max-age=86400(1 день). Снова проверьте. - Через неделю поднимите до
max-age=2592000(30 дней). - Через месяц —
max-age=31536000(1 год). - Только после этого, если действительно нужно, добавляйте
preloadи регистрируйтесь на hstspreload.org.
Mixed content: скрытая проблема после перехода
Вы настроили редирект, включили HSTS, всё работает — но PageSpeed всё равно ругается, и в консоли браузера красные предупреждения. Скорее всего, это mixed content: страница загружается по HTTPS, но внутри неё есть ресурсы (картинки, скрипты, стили), которые подключаются по HTTP.
Браузеры делят mixed content на два типа. Пассивный — картинки, видео, аудио по HTTP. Современные браузеры просто блокируют их без предупреждения. Активный — скрипты, стили, iframes по HTTP. Это критическая угроза, браузер блокирует жёстко.
Как это лечить? Для WordPress есть плагин Really Simple SSL — он автоматически заменяет HTTP на HTTPS в контенте базы данных. Но я предпочитаю делать это вручную через SQL, чтобы понимать что именно меняется:
-- Для WordPress: замена HTTP на HTTPS в контенте
UPDATE wp_posts
SET post_content = REPLACE(post_content, 'http://example.ru', 'https://example.ru')
WHERE post_content LIKE '%http://example.ru%';
-- Также нужно обновить опции сайта
UPDATE wp_options
SET option_value = REPLACE(option_value, 'http://example.ru', 'https://example.ru')
WHERE option_value LIKE '%http://example.ru%';
-- И мета-данные постов
UPDATE wp_postmeta
SET meta_value = REPLACE(meta_value, 'http://example.ru', 'https://example.ru')
WHERE meta_value LIKE '%http://example.ru%';
Для Битрикса ситуация немного другая — там URL часто хранятся в кеше и в настройках компонентов. После смены протокола нужно сбросить кеш полностью: через административную панель в разделе «Настройки → Инструменты → Кеш», а также вручную очистить папку /bitrix/cache/ и /bitrix/managed_cache/.
Ещё один источник mixed content, о котором часто забывают — внешние ресурсы. Если вы подключаете шрифты Google Fonts, скрипты аналитики или виджеты через HTTP-ссылки в коде темы или шаблона — это тоже mixed content. Проверяйте все хардкодированные URL.
Редиректы www и без www: выбираем одну версию
Это отдельная тема, которую часто путают с HTTPS-редиректами. На деле это два независимых редиректа, и их нужно настраивать вместе. Правила простые: выберите одну каноническую версию домена и перенаправляйте на неё всё остальное.
Я предпочитаю версию без www — она короче, и большинство современных сайтов используют именно её. Но это вкусовщина, главное — последовательность. Если у вас site.ru в Google Search Console добавлен без www, а редирект стоит на www — вы теряете сигналы и запутываете поисковики.
В Nginx правильная схема выглядит так: четыре варианта входящего трафика → один канонический. http://www.site.ru → https://site.ru, http://site.ru → https://site.ru, https://www.site.ru → https://site.ru. И только https://site.ru обслуживается нормально.
Для этого я обычно делаю два server-блока для HTTP (с www и без) и один отдельный server-блок для https://www, который редиректит на канонический вариант. Это чище, чем городить сложные if-условия в одном блоке.
По теме SEO-редиректов — рекомендую почитать подробную статью про 301 редиректы, там разобраны все нюансы передачи ссылочного веса.
Как проверить правильность настройки
После настройки редиректов и HSTS нужно убедиться, что всё работает как задумано. Вот мой чек-лист.
Проверка цепочки редиректов. Используйте curl в терминале — это самый надёжный способ:
# Проверяем редирект с HTTP
curl -I http://example.ru
# Должны увидеть:
# HTTP/1.1 301 Moved Permanently
# Location: https://example.ru/
# Проверяем редирект www
curl -I https://www.example.ru
# Должны увидеть:
# HTTP/1.1 301 Moved Permanently
# Location: https://example.ru/
# Проверяем HSTS заголовок
curl -I https://example.ru | grep -i strict
# Должны увидеть:
# strict-transport-security: max-age=31536000; includeSubDomains
Также использую онлайн-инструменты: SSL Labs (ssllabs.com/ssltest) даёт полный анализ SSL-конфигурации с оценкой A/B/C. Цель — оценка A+. securityheaders.com проверяет все заголовки безопасности, включая HSTS. redirect-checker.org показывает полную цепочку редиректов визуально.
Обратите внимание на длину цепочки редиректов. Каждый дополнительный редирект — это дополнительный round-trip и задержка. Идеально: один редирект с HTTP на HTTPS. Если у вас цепочка из трёх и более редиректов — это проблема для скорости и SEO. Подробнее о влиянии на скорость загрузки читайте в статье почему сайт медленно работает.
Особенности для Битрикс и Laravel
С Битриксом есть одна специфика: он любит самостоятельно управлять заголовками и иногда перезаписывает HSTS. Я видел случаи, когда Битрикс добавлял свой Strict-Transport-Security с max-age=0 — то есть фактически отключал HSTS. Это происходит в некоторых версиях ядра при определённых настройках безопасности.
Решение: либо настраивать HSTS в Nginx с директивой always (она перезаписывает заголовки из приложения), либо явно прописывать нужный заголовок в настройках Битрикса через /bitrix/.settings.php или через модуль «Безопасность» в административной панели.
Для Laravel всё намного чище. В Laravel 10+ есть middleware SecureHeaders, но честно говоря, я предпочитаю настраивать HSTS на уровне Nginx, а не в PHP-коде. Это быстрее и надёжнее. Если всё же нужно через Laravel — в app/Http/Middleware/TrustProxies.php добавьте нужные заголовки, а в конфиге session.php убедитесь, что 'secure' => true.
Ещё важный момент для Laravel: если приложение стоит за reverse proxy (Nginx → PHP-FPM), Laravel может не определить HTTPS корректно. Тогда генерируемые URL будут с HTTP, и вы получите mixed content несмотря на все настройки. Фикс — в AppServiceProvider:
Для Битрикса аналогичная проблема решается в /bitrix/php_interface/dbconn.php или через константу SITE_SERVER_NAME в конфигурации. Если работаете с Битриксом на постоянной основе, загляните на страницу поддержки Битрикс — такие вещи я часто разбираю в рамках технического аудита.
SEO-аспекты: что важно не упустить
После перехода на HTTPS и настройки редиректов нужно обновить ряд вещей с точки зрения SEO. Во-первых — Google Search Console. Добавьте HTTPS-версию домена как отдельный ресурс (если ещё не добавлена) и запросите переиндексацию. Google обычно подхватывает переезд на HTTPS быстро — за 2-4 недели, но лучше ускорить процесс через подачу sitemap.
Во-вторых — sitemap.xml. Убедитесь, что в нём все URL с HTTPS. Если генерируется автоматически (WordPress плагином, Битриксом), проверьте настройки домена в CMS. В-третьих — canonical теги. Они должны указывать на HTTPS-версию.
В-четвёртых — внешние ссылки и обратные ссылки. Это вы контролировать не можете, но редирект 301 передаёт большую часть ссылочного веса (по данным Google — практически весь, хотя исторически считалось, что теряется 10-15%).
По опыту: сайты, правильно переехавшие на HTTPS с одним чистым 301-редиректом, восстанавливают позиции в течение 2-6 недель. Сайты с кривой цепочкой редиректов или mixed content могут просесть на несколько месяцев. Так что делайте правильно с первого раза.
Если планируете комплексный технический аудит после перехода, обратите внимание на услугу доработки сайта — я помогаю разобраться с техническими проблемами, которые влияют на SEO и скорость.
Типичные ошибки, которые я вижу постоянно
За годы практики собрал целый зоопарк косяков. Перечислю самые частые.
Редирект только главной страницы. Настраивают редирект для example.ru, но забывают про example.ru/catalog/ и example.ru/blog/. Правило должно покрывать все пути — $request_uri в Nginx делает это автоматически.
Смешанные редиректы. На уровне Nginx редирект с HTTP на HTTPS, на уровне CMS — редирект с www на без www. В итоге получается цепочка из двух редиректов вместо одного. Всегда объединяйте логику редиректов в одном месте.
HSTS на HTTP-сервере. Видел такое несколько раз — добавляют HSTS-заголовок в HTTP server-блок. Это бессмысленно: браузер получает заголовок по небезопасному соединению и игнорирует его. HSTS работает только если отправляется по HTTPS.
Забытые поддомены. Включают includeSubDomains, не проверив все поддомены. Особенно часто страдают mail.*, ftp.*, dev.* и другие служебные поддомены без SSL-сертификата.
Короткий max-age на продакшене. Оставляют max-age=300 с тестирования и забывают поднять. В результате HSTS не даёт реального эффекта — браузер запоминает правило только на 5 минут.
Не обновлённые хардлинки в коде. В шаблоне или компонентах прописаны абсолютные URL вида http://example.ru/images/logo.png. После перехода на HTTPS это mixed content, который браузер заблокирует. Используйте относительные пути или protocol-relative URLs (//example.ru/...).
Честно говоря, большинство этих ошибок возникают не от незнания, а от спешки. Переход на HTTPS — это не «поставил галочку и забыл», это полноценная миграция, требующая тестирования. Прочитайте также полный чек-лист перехода на HTTPS — там я собрал всё, что нужно проверить перед и после переезда.
Итог: порядок действий
Подытожу правильный порядок настройки для нового сайта или при переезде существующего.
- Выпустите SSL-сертификат (Let's Encrypt через Certbot или от хостинга).
- Настройте HTTPS server-блок в Nginx/Apache и убедитесь, что сайт открывается по
https://. - Проверьте mixed content — откройте DevTools, вкладка Console и Network, фильтр по «Mixed Content».
- Устраните mixed content в базе данных, коде шаблона, внешних ресурсах.
- Добавьте 301-редирект с HTTP на HTTPS на уровне сервера.
- Настройте редирект www ↔ без www (выберите одну версию).
- Добавьте HSTS с
max-age=300, проверьте в браузере. - Постепенно увеличивайте
max-ageдо 31536000. - Обновите sitemap, canonical теги, настройки в Search Console.
- Через месяц стабильной работы решите, нужен ли preload.
Это не быстрый процесс, но именно такой подход позволяет избежать проблем. Я видел слишком много сайтов, где HTTPS «настроен», но на деле — полуработающий редирект, mixed content на каждой второй странице и HSTS с max-age=60. Делайте по-человечески с первого раза — сэкономите себе нервы и деньги на исправление.
Хотите защитить свой сайт с помощью HTTPS и HSTS?
Наши специалисты настроят безопасные редиректы и HSTS-политику для вашего сайта быстро и без ошибок.