Как принудительно включить HTTPS с помощью .htaccess
Принудительно включите HTTPS через .htaccess с правилами Apache, исправьте циклы за CDN и балансировщиками и настройте www и HSTS.
Чтобы принудительно перевести весь трафик на HTTPS в Apache, добавьте три строки в файл .htaccess в корневом каталоге сайта: RewriteEngine On, RewriteCond %{HTTPS} off и RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301].
Если вам когда-либо приходилось вставлять правило редиректа из ответа на форуме и затем наблюдать, как браузер зацикливался до полного отказа, — само правило, скорее всего, было корректным. Проблема, как правило, кроется в том, что находится перед вашим сервером.
Это правило перехватывает каждый запрос, поступающий по незашифрованному HTTP, и выполняет постоянный редирект на идентичный URL по HTTPS. Оно работает на Apache с включённым mod_rewrite и уже установленным SSL-сертификатом, а также предсказуемо даёт сбой в конкретных ситуациях — когда перед вашим origin-сервером находится CDN или балансировщик нагрузки. В этом руководстве сначала приводится готовое правило для копирования, затем варианты для конкретного домена, папки и www, далее — способы устранения петель редиректа, и наконец — что делать, если вы не используете Apache.
Ключевые выводы
- Каноническое правило проверяет
RewriteCond %{HTTPS} offи перенаправляет наhttps://%{HTTP_HOST}%{REQUEST_URI}, что сохраняет точный домен и путь, запрошенный посетителем, вместо жёсткого указания одного домена. R=301выполняет постоянный редирект, аLостанавливает дальнейшую обработку правил перезаписи; при тестировании сначала используйтеR(временный редирект 302), поскольку браузеры агрессивно кешируют 301, и отменить ошибочный редирект крайне сложно.- Принудительный переход на HTTPS работает только при наличии действительного TLS/SSL-сертификата. Редирект без сертификата сделает сайт недоступным, а не защищённым.
- За TLS-терминирующим прокси
%{HTTPS}никогда не принимает значениеon, поэтому правило зацикливается с ошибкойERR_TOO_MANY_REDIRECTS; вместо этого используйте проверку%{HTTP:X-Forwarded-Proto}. - Петля Cloudflare Flexible SSL — это ошибка конфигурации на стороне Cloudflare, которая устраняется изменением режима шифрования, а не редактированием
.htaccess.
Перед началом: SSL-сертификат и mod_rewrite
Принудительный переход на HTTPS работает только при наличии действительного TLS/SSL-сертификата, установленного на домене. Редирект на HTTPS без сертификата не обеспечивает безопасность сайта — он делает его недоступным, показывая браузерное предупреждение безопасности. (Термин «SSL-сертификат» является общепринятым в отрасли; фактически используемый протокол — TLS.) Убедитесь, что сертификат активен, открыв https://yourdomain.com напрямую в браузере и проверив наличие значка замка, прежде чем вносить изменения в .htaccess.
Приведённое ниже правило зависит от модуля Apache mod_rewrite, который по умолчанию включён на большинстве хостингов с общим доступом и cPanel. Файл .htaccess находится в корневом каталоге сайта — как правило, это public_html или document root домена. Редактировать его можно через File Manager в cPanel (включите «Show Hidden Files» для отображения скрытых файлов), по FTP или через SSH. Перед редактированием создайте резервную копию файла, чтобы иметь возможность восстановить его в случае ошибки в правиле.
Discover how at OpenReplay.com.
Правило .htaccess для принудительного перехода на HTTPS для всего трафика
Вставьте следующий код в файл .htaccess в корневом каталоге сайта, чтобы перенаправлять все HTTP-запросы на HTTPS:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Разбор по строкам: RewriteEngine On включает движок перезаписи. RewriteCond %{HTTPS} off активирует правило только тогда, когда соединение ещё не зашифровано. RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} перестраивает URL для HTTPS, при этом переменные %{HTTP_HOST} и %{REQUEST_URI} сохраняют точный домен и путь, запрошенный посетителем, — благодаря этому правило работает для нескольких доменов и никогда не добавляет www без явного указания.
В наборе флагов [L,R=301]: R=301 выполняет постоянный редирект, а L останавливает обработку правил перезаписи на данном правиле. При тестировании сначала используйте только R (временный редирект 302), поскольку браузеры жёстко кешируют 301, и исправить ошибочный редирект крайне неудобно; переходите к R=301 только после того, как убедитесь в корректной работе редиректа.
Не дублируйте RewriteEngine On. Если эта строка уже есть в файле, добавьте только RewriteCond и RewriteRule под ней.
Варианты: конкретный домен, папка и канонизация www
Чтобы принудительно включить HTTPS только для одного домена, когда несколько доменов указывают на один document root, добавьте условие для HTTP_HOST:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^yourdomain\.com [NC]
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Флаг NC делает сопоставление хоста нечувствительным к регистру. Для одновременного применения HTTPS и канонизации www/без www на сайте htaccessbook описан способ обернуть оба редиректа в блок mod_rewrite:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule (.*) https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
В опубликованной версии этого блока предполагается, что RewriteEngine On уже присутствует ранее в файле, поэтому выше он добавлен для обеспечения самостоятельной работы фрагмента. Первое правило переводит запрос на HTTPS. Второе добавляет www к хосту, у которого его нет. Обратите внимание, что [L] прекращает обработку, как только правило совпадает, поэтому обычный HTTP-запрос без www потребует двух редиректов, а не одного: сначала на HTTPS, затем на хост с www. Обёртка в <IfModule mod_rewrite.c> обеспечивает «мягкий» отказ (сайт продолжает работать по HTTP), а не ошибку 500, если mod_rewrite не загружен.
Ручное комбинирование этих правил становится трудоёмким, когда в одном файле сочетаются HTTPS, канонизация www, несколько редиректов и блок кеширования — лишний флаг или правило не на своём месте обязательно даст о себе знать в продакшене. Генератор htaccess от OpenReplay собирает файл из набора переключателей: принудительный HTTPS, добавление или удаление www, редиректы 301 или 302, включение gzip и кеширования браузера, блокировка IP-адресов, настройка пользовательских страниц ошибок. Результат снабжён комментариями, обновляется по мере изменения параметров и работает полностью в браузере — файл можно скопировать или скачать и сравнить с уже имеющимся.
Устранение ERR_TOO_MANY_REDIRECTS за CDN или балансировщиком нагрузки
Если редирект вызывает ошибку ERR_TOO_MANY_REDIRECTS, браузер прошёл слишком много переходов и прекратил попытки. Как правило, причиной является TLS-терминирующий прокси или балансировщик нагрузки. TLS завершается на прокси, поэтому %{HTTPS} никогда не принимает значение on на origin-сервере, правило срабатывает при каждом запросе, и петля никогда не разрывается. Решение — доверять заголовку переданной схемы:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
Здесь RewriteCond %{HTTP:X-Forwarded-Proto} !https считывает заголовок X-Forwarded-Proto, устанавливаемый прокси, и правило срабатывает только тогда, когда исходное соединение посетителя было по HTTP. Перед переходом к R=301 протестируйте с флагом R.
Петля Cloudflare Flexible SSL — это отдельная проблема с отдельным решением. При Flexible-шифровании соединение между Cloudflare и вашим сервером не зашифровано, поэтому правило на origin-сервере, требующее HTTPS, постоянно перенаправляет запрос по кругу. Cloudflare предлагает два выхода: отключить HTTPS-редирект на origin-сервере или перевести зону на режим Full или строже, что требует наличия сертификата непосредственно на origin-сервере. Оба изменения выполняются в панели управления Cloudflare, а не в .htaccess. Посетитель в режиме Flexible всё равно использует HTTPS, а схема, которую Cloudflare передаёт в X-Forwarded-Proto, отражает соединение самого посетителя, поэтому описанная выше проверка заголовка здесь не даст ложных срабатываний. Тем не менее корректное решение — исправить режим шифрования.
После любых изменений перед повторным тестированием очистите кеш браузера и cookies, поскольку закешированный 301 может скрыть исправление. Условная петля, затрагивающая только пользователей, приходящих через один проксированный путь, не видна при единичной ручной проверке из собственного браузера. Запись сессий на сайте после миграции позволяет выявить такую периодическую петлю редиректов и проблемы со смешанным контентом — они проявляются как паттерн бесконечных переходов у реальных пользователей.
Когда .htaccess — не лучший инструмент
.htaccess работает только на Apache и читается исключительно на Apache-хостинге. В Nginx файла .htaccess не существует. Принудительный переход на HTTPS настраивается через серверный блок, который прослушивает порт 80 и возвращает редирект:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}
Оставляйте return 301 только в блоке для порта 80; размещение его внутри блока 443 воссоздаёт петлю. На современных стеках применение HTTPS нередко лучше настраивать на уровне CDN, платформы или балансировщика нагрузки, а не в конфигурации сервера.
После того как редирект заработает, усильте защиту с помощью заголовка HSTS, чтобы браузеры автоматически подключались по HTTPS, минуя незащищённый HTTP-запрос. HSTS определён в RFC 6797; шпаргалка OWASP по HSTS рекомендует Strict-Transport-Security: max-age=63072000; includeSubDomains; preload. Относитесь к preload как к необратимому шагу: удаление домена из списка preload — процесс долгий, и пока вы ждёте, посетители могут потерять доступ к домену и всему, что находится под ним, если вам когда-либо придётся вернуться к HTTP.
Выберите правило, подходящее для вашей конфигурации, разверните его с временным редиректом 302, убедитесь, что редирект выполняется за один переход, затем переведите его в постоянный 301 и добавьте поверх HSTS. Такая последовательность обеспечивает принудительный переход на HTTPS без петель редиректов и закешированных ошибок, способных превратить пятиминутное изменение в полноценный инцидент.
Часто задаваемые вопросы
В чём разница между редиректом 301 и 302 при принудительном переходе на HTTPS?
301 — это постоянный редирект, 302 — временный. Браузеры агрессивно кешируют 301 и хранят их долгое время, поэтому ошибочный 301 сложно отменить. При тестировании HTTPS-редиректа сначала используйте R (302) в флагах RewriteRule, убедитесь, что редирект корректно выполняется за один переход, а затем переходите к R=301 для постоянной версии.
Как проверить корректность HTTPS-редиректа, не очищая кеш браузера?
Выполните команду curl -IL http://yourdomain.com в командной строке. Флаг -I запрашивает только заголовки, а -L следует за редиректами, поэтому вы видите полную цепочку. При корректной настройке возвращается один редирект 301 с заголовком Location, указывающим на https-URL, а затем код 200 для защищённого адреса. Если вы видите повторяющиеся 301 или редирект обратно на http — у вас петля. Этот метод детерминирован, в отличие от проверки закешированной вкладки браузера.
Почему мой HTTPS-редирект вызывает ошибку 500 вместо редиректа?
Ошибка 500 обычно означает, что mod_rewrite не загружен, но ваше правило напрямую вызывает RewriteEngine или RewriteRule. Оберните правила в блок IfModule mod_rewrite.c, чтобы Apache пропускал их и продолжал работать по HTTP, а не выдавал ошибку при отсутствии модуля. На большинстве хостингов с общим доступом и cPanel mod_rewrite включён по умолчанию, но использование блока-обёртки является безопасной практикой, если вы не можете это подтвердить.
Работает ли правило HTTPS в .htaccess с AWS Application Load Balancer или другими TLS-терминирующими прокси?
Стандартное правило %{HTTPS} off — нет. Когда AWS ALB или аналогичный балансировщик нагрузки терминирует TLS, зашифрованное соединение завершается на прокси, и ваш Apache origin-сервер всегда получает обычный HTTP, поэтому %{HTTPS} никогда не принимает значение on, и правило зацикливается с ошибкой ERR_TOO_MANY_REDIRECTS. Вместо этого используйте RewriteCond %{HTTP:X-Forwarded-Proto} !https, которое считывает заголовок, устанавливаемый прокси для передачи исходного протокола посетителя.