我在 SSL 终止反向代理(在我的例子中是 Traefik)后面使用 apache 2.4.57。 Traefik 接受 https 请求并将它们代理到 apache 端口 80,并设置以下 HTTP 标头:
X-Forwarded-Proto
和 X-Forwarded-For
。
我的问题是我无法让 apache 识别出请求实际上是使用 https 方案。这是有问题的,因为我有大量
RewriteRule
配置,这些配置会导致 302 响应,其中包含这样的 http 方案:location: http://myhostname.org/mypath
。这有时会导致我的应用程序出现 MixedContent 错误。
理想情况下,我想将其添加到我的
VirtualHost
配置中:
SetEnvIf X-Forwarded-Proto "https" HTTPS=on
但是
HTTPS
变量始终保持 off
。事实上,即使我配置了 SetEnv HTTPS on
,HTTPS
变量仍然保持 off
。
缩写的配置是这样的:
<VirtualHost *:80>
SetEnvIf X-Forwarded-Proto "https" HTTPS=on
RewriteEngine On
# Debug: Show X-Forwarded-Proto header and HTTPS variable
RewriteRule ^/debug$ /debug?xfp=%{HTTP:X-Forwarded-Proto}&https=%{HTTPS} [R,L]
# Lots of other RewriteRules below...
</VirtualHost>
当我尝试使用curl 进行测试时,我得到:
curl -v https://myhostname.org/debug 2>&1 |grep location
< location: http://myhostname.org/debug?xfp=https&https=off
为什么这不起作用?如何强制打开
HTTPS
并让我所有的 RewriteRules
返回带有 https 的位置?
SetEnvIf
指令(在SetEnvIf X-Forwarded-Proto "https" HTTPS=on
中)没有设置HTTPS=on
,因为它仅在读取请求标头之后设置环境变量。这意味着依赖于此环境变量的 RewriteRule
指令不会在同一请求中获取更新的值。您可以在 Apache 中尝试 ,但由于在您的情况下,Traefik 已经发送
X-Forwarded-Proto
,您可以使用条件
RewriteCond
和 RewriteRule
来操作 URL 模式。
<VirtualHost *:80>
RewriteEngine On
# Set an environment variable if X-Forwarded-Proto is https
RewriteCond %{HTTP:X-Forwarded-Proto} ^https$
RewriteRule ^ - [E=HTTP_SCHEME:https]
# Fallback to http if the above condition did not match
RewriteCond %{ENV:HTTP_SCHEME} ^$
RewriteRule ^ - [E=HTTP_SCHEME:http]
# Your existing RewriteRules here, but modify to use the determined scheme
RewriteRule ^/debug$ %{ENV:HTTP_SCHEME}://%{HTTP_HOST}/debug?xfp=%{HTTP:X-Forwarded-Proto}&https=%{ENV:HTTP_SCHEME} [R,L]
# other RewriteRules
</VirtualHost>
RewriteCond
用于检查
X-Forwarded-Proto
。如果是“https”,我们将环境变量
HTTP_SCHEME
设置为“https”。然后在您的
RewriteRule
中,我们使用此环境变量来构造 URL。这应该会在 302 响应的
Location
标头中生成具有正确方案的 URL。