В современном вебе стоит использовать HTTPS, и желательно настроить автоматический редирект на HTTPS, если у пользователя достаточно свежий браузер. Предлагаю конфиг для Apache, который используется на моих сайтах с 2020 года, пройдя через несколько небольших доработок.
Фишки этого конфига:
- Авторедирект на каноничный хост, или автоматическое удаление или добавление WWW из хоста.
- Если сайт открыт через HTTPS, то автоматически настраивается Upgrade-Insecure-Requests (все ресурсы, ссылки на которые указаны через HTTP, будут всё равно загружены через HTTPS) и Strict-Transport-Security (браузер всегда будет открывать сайт по HTTPS).
- Если браузер слишком старый и не поддерживает Upgrade-Insecure-Requests или Let's Encrypt, то редирект на HTTPS не производится, сайт продолжает работать по HTTP.
- Пользователь может установить принудительный редирект на HTTPS (forcessl=1), принудительно отключить редирект (forcessl=0), или вернуть автоматический режим (forcessl=auto), передав любой странице по любому протоколу параметр forcessl с нужным значением. Выбор запоминается в cookies.
Код для .htaccess
Поместите следующий код в самое начало файла .htaccess в корне вашего сайта. Требуется Apache 2.4+ с включёнными модулями mod_rewrite, mod_headers и mod_setenvif.
RewriteEngine On RewriteBase / # ---------------------------------------------------------------------------------------------------------------------- # Force HTTPS and canonical host if required. # ---------------------------------------------------------------------------------------------------------------------- # Set canonical host. RewriteRule ^ - [E=FORCE_HOST:%{HTTP_HOST}] # Detect current scheme. REQUEST_SCHEME is not reliable since Apache might be behind Nginx. RewriteRule ^ - [E=REQ_SCHEME:http] RewriteCond %{HTTPS} ^on$ [NC,OR] RewriteCond %{HTTP:X-Forwarded-Proto} https [NC,NV] RewriteRule ^ - [E=REQ_SCHEME:https] # Force canonical host. We should do it before we try to set any cookies or any other redirects. RewriteCond expr "%{ENV:FORCE_HOST} != '' && tolower(%{HTTP_HOST}) != tolower(%{ENV:FORCE_HOST})" RewriteRule ^/?(.*)$ %{ENV:REQ_SCHEME}://%{ENV:FORCE_HOST}/$1 [NE,R=301,END] # Allow UIR if Upgrade-Insecure-Requests is in the request headers. # UIR support: IE18+ (2018), Firefox 48+ (2016), Chrome 44+ (2015), Safari 10.1+ (2017, MacOS 10.10+). RewriteRule ^ - [E=PERMIT_UIR:0] RewriteCond %{HTTP:Upgrade-Insecure-Requests} ^1$ RewriteRule ^ - [E=PERMIT_UIR:1] # Allow Strict-Transport-Security if UIR is supported, and browser trusts Let's Encrypt's "ISRG Root X1": # - OS: Windows 7+ (2018/07/31), Android 7.1.1+ (2017), iOS 10+ (2017), MacOS 10.12.1+ (2016). # - Browsers: Firefox 50+ (2016), Chrome 108+ (2022, Windows/MacOS) 114+ (2023, Linux/ChromeOS) 115+ (2023, Android). # STS support: IE11+ (2015), Firefox 4+ (2011), Chrome 4+ (2010), Safari 7+ (2013), Android 4.4+ (2013). # Windows XP: Firefox 52- (2017), Chrome 49- (2016), IE8. Windows 7-8.1: Firefox 115- (2023), Chrome 109- (2023), IE11. RewriteRule ^ - [E=PERMIT_STS:0] RewriteCond %{ENV:PERMIT_UIR} ^1$ RewriteCond %{HTTP_USER_AGENT} !Android\s([1-6]\.|7\.0|7\.1\.0) RewriteCond %{HTTP_USER_AGENT} !Windows\sNT\s(5\.|6\.0) RewriteCond %{HTTP_USER_AGENT} !Mac\sOS\sX\s10[_.]1[0-2] RewriteCond %{HTTP_USER_AGENT} !(iPhone|iPad);\sCPU\s(iPhone\s)?OS\s[1-9][_.] RewriteCond %{HTTP_USER_AGENT} !Firefox\/[1-4]?[0-9]\. RewriteCond %{HTTP_USER_AGENT} !Chrome\/([1-9]?[0-9]|10[0-7])\. RewriteCond %{HTTP_USER_AGENT} !Android.+Chrome\/(10[8-9]|11[0-4])\. RewriteRule ^ - [E=PERMIT_STS:1] # Force HTTPS if STS is allowed and forcessl cookie is not 0. RewriteRule ^ - [E=URL_SCHEME:%{ENV:REQ_SCHEME}] RewriteCond %{ENV:PERMIT_STS} ^1$ RewriteCond %{HTTP_COOKIE} !(?:^|;)\s*forcessl=0\s*(?:;|$) RewriteRule ^ - [E=URL_SCHEME:https] # Use HTTPS if forcessl cookie is 1. RewriteCond %{HTTP_COOKIE} (?:^|;)\s*forcessl=1\s*(?:;|$) RewriteRule ^ - [E=URL_SCHEME:https] # Set or remove the forcessl cookie depending on the forcessl URL parameter. RewriteCond %{QUERY_STRING} (?:^|&)forcessl=(?:auto|-|)(?:&|$) RewriteRule ^ - [E=SET_FORCESSL_COOKIE:-,E=URL_SCHEME:http] RewriteCond %{QUERY_STRING} (?:^|&)forcessl=0(?:&|$) RewriteRule ^ - [E=SET_FORCESSL_COOKIE:0,E=URL_SCHEME:http] RewriteCond %{QUERY_STRING} (?:^|&)forcessl=1(?:&|$) RewriteRule ^ - [E=SET_FORCESSL_COOKIE:1,E=URL_SCHEME:https] # Set forcessl=1 if STS isn't allowed, forcessl cookie isn't set, and current scheme is HTTPS. # RewriteCond %{ENV:REQ_SCHEME} ^https$ # RewriteCond %{ENV:PERMIT_STS} !^1$ # RewriteCond %{HTTP_COOKIE} !(?:^|;)\s*forcessl=[01]\s*(?:;|$) # RewriteCond %{ENV:SET_FORCESSL_COOKIE} !^[-01]$ # RewriteRule ^ - [E=SET_FORCESSL_COOKIE:1] # Canonical prefix. RewriteRule ^ - [E=URL_PREFIX:%{ENV:URL_SCHEME}://%{HTTP_HOST}] # Decide if we want to send STS and UIR headers. Never send them when current request is HTTP. RewriteCond %{ENV:REQ_SCHEME} ^https$ RewriteRule ^ - [E=SET_FORCESTS_HEADER:0,E=SET_FORCEUIR_HEADER:0] RewriteCond %{ENV:REQ_SCHEME} ^https$ RewriteCond %{ENV:URL_SCHEME} ^https$ RewriteRule ^ - [E=SET_FORCESTS_HEADER:%{ENV:PERMIT_STS},E=SET_FORCEUIR_HEADER:%{ENV:PERMIT_UIR}] # Try to fix stupid adding of the "REDIRECT_" prefix to environment variable names on URL rewrite. SetEnvIf REDIRECT_PERMIT_UIR (.+) PERMIT_UIR=$1 SetEnvIf REDIRECT_PERMIT_STS (.+) PERMIT_STS=$1 SetEnvIf REDIRECT_REQ_SCHEME (.+) REQ_SCHEME=$1 SetEnvIf REDIRECT_URL_SCHEME (.+) URL_SCHEME=$1 SetEnvIf REDIRECT_URL_PREFIX (.+) URL_PREFIX=$1 SetEnvIf REDIRECT_SET_FORCESSL_COOKIE (.+) SET_FORCESSL_COOKIE=$1 SetEnvIf REDIRECT_SET_FORCESTS_HEADER (.+) SET_FORCESTS_HEADER=$1 SetEnvIf REDIRECT_SET_FORCEUIR_HEADER (.+) SET_FORCEUIR_HEADER=$1 # Send cookies in modern format with Max-Age. In old browsers like IE11 they will be stored until the browser is closed. # According to RFC 6265, "host-only" cookie (which won't be sent to subdomains) shouldn't have "Domain=" attribute. Header always add Set-Cookie "forcessl=; Path=/; Max-Age=-1" "expr= '%{ENV:SET_FORCESSL_COOKIE}' == '-'" Header always add Set-Cookie "forcessl=0; Path=/; Max-Age=34560000" "expr= '%{ENV:SET_FORCESSL_COOKIE}' == '0'" Header always add Set-Cookie "forcessl=1; Path=/; Max-Age=34560000" "expr= '%{ENV:SET_FORCESSL_COOKIE}' == '1'" # Send the STS and UIR headers if required. 2592000 seconds = 30 days. Header always set Strict-Transport-Security "max-age=2592000" "expr= '%{ENV:SET_FORCESTS_HEADER}' == '1'" Header always set Strict-Transport-Security "max-age=0" "expr= '%{ENV:SET_FORCESTS_HEADER}' == '0'" Header always set Content-Security-Policy "upgrade-insecure-requests" "expr= '%{ENV:SET_FORCEUIR_HEADER}' == '1'" # Remove the forcessl URL parameter. RewriteCond %{QUERY_STRING} ^(.*&|)forcessl=(?:auto|[-01]|)(?:&(.*)|)$ RewriteRule ^/?(.*)$ %{ENV:URL_PREFIX}/$1?%1%2 [NE,R=302,END] # Redirect to HTTPS or HTTP if desired scheme is different from used in this request. RewriteCond %{ENV:REQ_SCHEME}:%{ENV:URL_SCHEME} !^(.+):\1$ RewriteRule ^/?(.*)$ %{ENV:URL_PREFIX}/$1 [NE,R=302,END] # ----------------------------------------------------------------------------------------------------------------------
В самом начале в переменную FORCE_HOST заносится каноничный хост, куда попутно будет сделан авторедирект при необходимости. В примере выше туда заносится просто текущий хост, то есть функция редиректа на каноничный хост отключена:
RewriteRule ^ - [E=FORCE_HOST:%{HTTP_HOST}]
Если вы хотите перенаправлять пользователя на хост без WWW, используйте такой вариант:
RewriteCond %{HTTP_HOST} ^(?:www\.)+(.+) [NC] RewriteRule ^ - [E=FORCE_HOST:%1]
Либо используйте такой вариант для автоматического добавления WWW к текущему хосту:
RewriteCond %{HTTP_HOST} ^(?:www\.)+(.+) [NC] RewriteRule ^ - [E=FORCE_HOST:www.%1]
Если у вас несколько алиасов, и все должны вести на каноничный хост, задавайте его таким образом:
RewriteRule ^ - [E=FORCE_HOST:example.com]
Если вам нужно добавить какие-то редиректы внутри сайта, то их следует размещать в самом конце. Используйте переменную %{ENV:URL_PREFIX} вместо явного указания протокола и хоста (она содержит строку вида https://example.com), или переменную %{ENV:URL_SCHEME} в качестве предпочитаемого протокола (там будет либо http, либо https).
Комментарии временно закрыты. Обновите эту страницу через минуту.