Tomcat 在防火墙后面的 Apache 后面:AJP 忽略 X-Forwarded-Proto

Tomcat behind Apache behind Firewall: AJP ignores X-Forwarded-Proto

对于 https 流量,我们有以下设置:

我们已将 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 会干扰其他模块,则可能会有用。