我正在尝试弄清楚如何将 http 流量重定向到 https。我使用 varnish 运行 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>
答案1
实现目标的最简单方法是将以下代码添加到.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来说很重要。
清漆和 TLS
Varnish 仅处理 HTTP 流量并以纯 HTTP 与 Apache 通信。您可能会终止TLS 连接别处。
因此,即使你正在执行 HTTPS 请求,Varnish 也会向 Apache 发出 HTTP 请求来获取内容。这将始终导致301 重定向,无论初始连接使用何种协议。
最终结果是一个无限循环,这是我们想要避免的。这就是为什么X-Forwarded-Proto
在虚拟主机终止 TLS 的系统。
设置X-Forwarded-Proto
标题
以下代码片段似乎负责 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
或未设置标题时才会重定向。
为 Varnish 创建缓存变体
这种条件重定向策略会对你的缓存产生影响:Varnish 将存储301重定向并提供给所有客户端。
问题在于 Varnish 无法识别协议的差异。对于 Varnish 来说,一切都是纯 HTTP。Apache 需要通知 Varnish,它应该为 HTTP 版本和 HTTPS 版本分别保存一份副本。
这被称为缓存变化HTTP 允许您使用Vary
标头来实现这一点。在这种情况下,我们将根据不同的值进行更改X-Forwarded-Proto
。
这就是为什么您Header append Vary: X-Forwarded-Proto
需要.htacccess file
。
Varnish 将解释此信息并在缓存中创建此页面的两个版本。如果您未指定Vary: X-Forwarded-Proto
,Varnish 将始终重定向到 HTTPS(即使对于 HTTPS 请求)或从不重定向到 HTTPS(即使对于普通 HTTP 请求)。
结论
制作 Apache协议感知通过利用X-Forwarded-Proto
应该在终止 TLS 的 Apache vhost 中设置的功能。
最后,制作 Varnish协议感知也可以通过使用X-Forwarded-Proto
标题作为Vary
值。