Tomcat 在防火墙后面的 Apache 后面:AJP 忽略 X-Forwarded-Proto
Tomcat behind Apache behind Firewall: AJP ignores X-Forwarded-Proto
对于 https 流量,我们有以下设置:
- 防火墙:终止 https,添加 "X-Forwarded-Proto: https",通过 http
转发到 Apache
- Apache:通过 AJP
转发到 Tomcat
- Tomcat:通过AJP-connector
接收请求
我们已将 RemoteIpValve 添加到 Tomcat 的 server.xml:
<Valve className="org.apache.catalina.valves.RemoteIpValve"
remoteIpHeader="x-forwarded-for"
protocolHeader="x-forwarded-proto"
/>
如果我们跳过 Apache 并使用常规 HTTP-Connector 从防火墙直接转发到 Tomcat,它就会起作用。在这种情况下 Tomcat 使用 https 进行重定向和基本 url。
但是一旦我们通过 Apache 和 AJP,X-Forwarded-Proto header 似乎被忽略了。我们检查过,X-Forwarded-Proto header 仍然存在于 Tomcat 的请求中。
我猜 Tomcat 是通过 AJP 告诉 front-end 使用的是哪种协议(http 或 https)。也许这不会发生?我们是否需要以某种方式告诉 Apache 为 AJP 考虑 X-Forwarded-Proto?
Apache 虚拟主机配置:
<VirtualHost *:80>
ServerName www.myserver.biz
JkMount /* LoadBalancerHD
</VirtualHost>
workers.properties:
worker.list=LoadBalancerHD
worker.LoadBalancerHD.balance_workers=HDNode1,HDNode2
worker.LoadBalancerHD.type=lb
worker.LoadBalancerHD.sticky_session=True
worker.HDNode1.type=ajp13
worker.HDNode1.host=webserver01
worker.HDNode1.port=8010
worker.HDNode1.distance=0
worker.HDNode2.type=ajp13
worker.HDNode2.port=8010
worker.HDNode2.host=webserver02
worker.HDNode2.distance=1
研究 mod_jk 文档后,我发现 mod_jk 评估 Apache 环境变量 HTTPS
以检测 https。如果 Apache 自己处理 https 流量,通常此变量由 mod_ssl 设置。但事实并非如此,因为 HTTPS 已经在 Apache 之前终止。
只需根据 http header 设置环境变量即可:
SetEnvIfNoCase X-Forwarded-Proto https HTTPS=on
顺便说一句:由 mod_jk 评估的环境变量可以用 JkHTTPSIndicator
指令更改(参见 mod_jk docs)。所以下面做同样的事情:
SetEnvIfNoCase X-Forwarded-Proto https EXTERNAL_TRAFFIC_IS_HTTPS=on
JkHTTPSIndicator EXTERNAL_TRAFFIC_IS_HTTPS
如果更改 HTTPS
会干扰其他模块,则可能会有用。
对于 https 流量,我们有以下设置:
- 防火墙:终止 https,添加 "X-Forwarded-Proto: https",通过 http 转发到 Apache
- Apache:通过 AJP 转发到 Tomcat
- Tomcat:通过AJP-connector 接收请求
我们已将 RemoteIpValve 添加到 Tomcat 的 server.xml:
<Valve className="org.apache.catalina.valves.RemoteIpValve"
remoteIpHeader="x-forwarded-for"
protocolHeader="x-forwarded-proto"
/>
如果我们跳过 Apache 并使用常规 HTTP-Connector 从防火墙直接转发到 Tomcat,它就会起作用。在这种情况下 Tomcat 使用 https 进行重定向和基本 url。
但是一旦我们通过 Apache 和 AJP,X-Forwarded-Proto header 似乎被忽略了。我们检查过,X-Forwarded-Proto header 仍然存在于 Tomcat 的请求中。
我猜 Tomcat 是通过 AJP 告诉 front-end 使用的是哪种协议(http 或 https)。也许这不会发生?我们是否需要以某种方式告诉 Apache 为 AJP 考虑 X-Forwarded-Proto?
Apache 虚拟主机配置:
<VirtualHost *:80>
ServerName www.myserver.biz
JkMount /* LoadBalancerHD
</VirtualHost>
workers.properties:
worker.list=LoadBalancerHD
worker.LoadBalancerHD.balance_workers=HDNode1,HDNode2
worker.LoadBalancerHD.type=lb
worker.LoadBalancerHD.sticky_session=True
worker.HDNode1.type=ajp13
worker.HDNode1.host=webserver01
worker.HDNode1.port=8010
worker.HDNode1.distance=0
worker.HDNode2.type=ajp13
worker.HDNode2.port=8010
worker.HDNode2.host=webserver02
worker.HDNode2.distance=1
研究 mod_jk 文档后,我发现 mod_jk 评估 Apache 环境变量 HTTPS
以检测 https。如果 Apache 自己处理 https 流量,通常此变量由 mod_ssl 设置。但事实并非如此,因为 HTTPS 已经在 Apache 之前终止。
只需根据 http header 设置环境变量即可:
SetEnvIfNoCase X-Forwarded-Proto https HTTPS=on
顺便说一句:由 mod_jk 评估的环境变量可以用 JkHTTPSIndicator
指令更改(参见 mod_jk docs)。所以下面做同样的事情:
SetEnvIfNoCase X-Forwarded-Proto https EXTERNAL_TRAFFIC_IS_HTTPS=on
JkHTTPSIndicator EXTERNAL_TRAFFIC_IS_HTTPS
如果更改 HTTPS
会干扰其他模块,则可能会有用。