Я пытаюсь понять, как перенаправить HTTP-трафик на https. Я запустил apache2 с лаком. Кто-то более осведомленный, чем я, установил это для меня на других сайтах. Я создал новый сайт, имитирующий конфигурацию apache для одного из известных хороших сайтов, на котором работает перенаправление, но мне не удалось заставить его работать для нового сайта; HTTP-трафик просто появляется в браузере как обычный HTTP-трафик. Вот мой файл конфигурации apache:
<VirtualHost *>
ServerName thesite.org
ServerAlias *.thesite.org
Use letsencrypt-challenge thesite.org
Use ssl-upgrade thesite.org
# replace the brackets and string with the appropriate string as indicated
DocumentRoot /home/sites/wp_sites/thesite
ScriptAlias /cgi-bin/ /home/thesite/cgi-bin/
ScriptAlias /cgi /home/thesite/cgi-bin/
# not a typo, the user name is entered twice in the line below
SuexecUserGroup thesite thesite
# THIS HAS TO BE CORRECT. Double and triple check your typing here!
Use site_logging thesite
# These settings are the same for every site
ErrorDocument 404 /index.php
Use default_expire
Options IncludesNOEXEC FollowSymLinks
Use default_deny
Use default_php_fastcgi
</VirtualHost>
<VirtualHost *:443>
ServerName thesite.org
ServerAlias *.thesite.org
Use letsencrypt-challenge thesite.org
Use letsencrypt-ssl thesite.org
Use ssl-proxy thesite.org
#ProxyPass / http://thesite.org/
# ProxyPassReverse / http://thesite.org/
</VirtualHost>
И вот соответствующие макросы:
<Macro ssl-redirect $server_redirect>
RewriteCond expr "%{HTTP_HOST} != '$server_redirect'"
RewriteRule /?(.*) "https://$server_redirect/$1" [L,NE]
</Macro>
<Macro ssl-upgrade $server_upgrade>
Use ssl-redirect "$server_upgrade"
<If "! req_novary('X-Forwarded-Proto') =~ /https/">
Redirect / "https://$server_upgrade/"
</If>
</Macro>
<Macro ssl-proxy $server_proxy>
Use letsencrypt-challenge "$server_proxy"
Use letsencrypt-ssl "$server_proxy"
Use ssl-redirect "$server_proxy"
ProxyPass / "http://$server_proxy/"
ProxyPassReverse / "http://$server_proxy/"
</Macro>
<Macro letsencrypt-ssl $server>
SSLEngine On
SSLProtocol all -SSLv2 -SSLv3
SSLHonorCipherOrder on
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"
SSLCertificateFile "/etc/letsencrypt/live/$server/fullchain.pem"
SSLCertificateKeyFile "/etc/letsencrypt/live/$server/privkey.pem"
RequestHeader set X-Forwarded-Proto "https"
</Macro>
<Macro letsencrypt-challenge $server>
<Directory /etc/apache2/letsencrypt/$server/.well-known/acme-challenge>
Require all granted
</Directory>
RewriteEngine On
RewriteRule /.well-known/acme-challenge/(.*) /etc/apache2/letsencrypt/$server/.well-known/acme-challenge/$1 [L]
</Macro>
Самый простой способ достичь своей цели - это добавить следующий код в файл .htaccess
в корне вашего документа:
SetEnvIf X-Forwarded-Proto "https" HTTPS=on
Header append Vary: X-Forwarded-Proto
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP:X-Forwarded-Proto} !https [NC]
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
Что делает эти правила перезаписи настолько специфичным является тот факт, что они поддерживают протокол . Это важно для Varnish.
Varnish обрабатывает только HTTP-трафик и взаимодействует с Apache по обычному HTTP. Вы, вероятно, разорвете соединение TLS где-нибудь еще.
Таким образом, даже если вы выполняете запрос HTTPS, Varnish выполнит HTTP-запрос к Apache, чтобы получить контент. Это всегда будет приводить к перенаправлению 301 , независимо от протокола, который использовался для начального соединения.
Конечным результатом является бесконечный цикл, которого мы хотим избежать. Вот почему рекомендуется выставлять заголовок X-Forwarded-Proto
в vhost системы, завершающей TLS.
X-Forwarded-Proto
header Следующий фрагмент кода, по-видимому, отвечает за завершение TLS. Однако часть, где трафик HTTPS проксируется на Varnish, закомментирована.
<VirtualHost *:443>
ServerName thesite.org
ServerAlias *.thesite.org
Use letsencrypt-challenge thesite.org
Use letsencrypt-ssl thesite.org
Use ssl-proxy thesite.org
#ProxyPass / http://thesite.org/
# ProxyPassReverse / http://thesite.org/
</VirtualHost>
Вам, вероятно, придется это исправить. Следующее выражение также должно быть добавлено, чтобы раскрыть протокол входящего запроса:
RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
Пожалуйста, убедитесь, что mod_headers
включен, если вы хотите установить заголовки.
Если установлено HTTPS-соединение, Apache вернет следующий заголовок ответа:
X-Forwarded-Proto: https
Правило перезаписи, которым я поделился, учитывает это и будет перенаправлять, только если X-Forwarded-Proto
равно http
или если заголовок не set.
Эта стратегия условного перенаправления повлияет на ваш кеш: Varnish сохранит перенаправление 301 и предоставит его всем клиентам.
Проблема заключается в том, что Varnish не знает разницы в протоколе. Для Varnish все просто HTTP. Apache должен проинформировать Varnish о том, что он должен предоставить копию для версии HTTP и копию для версии HTTPS.
Это называется вариантом кеша , а HTTP позволяет использовать Vary
для этого. В этом случае мы собирались варьировать различные значения, которые есть у X-Forwarded-Proto
.
Вот почему вам нужно Header append Vary: X-Forwarded-Proto
в вашем .htacccess файл
.
Varnish интерпретирует это и создаст 2 версии этой страницы в кеше. Если вы не укажете Vary: X-Forwarded-Proto
, Varnish будет либо всегда перенаправлять на HTTPS, даже для HTTPS-запроса, либо никогда, даже для простых HTTP-запросов.
Сделайте протокол Apache осведомленным , используя X-Forwarded-Proto
, который должен быть установлен на виртуальном хосте Apache, на котором вы завершаете TLS.
И, наконец, сделайте так, чтобы протокол Varnish знал , а также с помощью заголовка X-Forwarded-Proto
в качестве значения Vary
.