apachetomcathttpsmod-jkajp

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


We have following setup in case of https traffic:

We have added the RemoteIpValve to Tomcat's server.xml:

<Valve className="org.apache.catalina.valves.RemoteIpValve"
                   remoteIpHeader="x-forwarded-for"
                   protocolHeader="x-forwarded-proto"
            />

It works if we skip Apache and forward straight from the firewall to Tomcat with a regular HTTP-Connector. In that case Tomcat uses https for redirect and base urls.

But once we go through Apache and AJP, the X-Forwarded-Proto header seems to be ignored. We checked, the X-Forwarded-Proto header is still present on Tomcat's request.

I guess Tomcat is told through AJP which front-end protocol is used (http or https). Maybe this doesn't happen? Do we need to tell Apache somehow to consider X-Forwarded-Proto for AJP?

Apache VirtualHost configuration:

<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

Solution

  • After studying the mod_jk docs I found out that mod_jk evaluates the Apache environment variable HTTPS in order to detect https. Usually this variable is set by mod_ssl if Apache processes the https traffic itself. But this is not the case since HTTPS is already terminated before Apache.

    Simply setting the environment variable based on the http header does the trick:

    SetEnvIfNoCase X-Forwarded-Proto https HTTPS=on
    

    BTW: The the environment variable which is evaluated by mod_jk can be changed with the JkHTTPSIndicator directive (see mod_jk docs). So following does the same:

    SetEnvIfNoCase X-Forwarded-Proto https EXTERNAL_TRAFFIC_IS_HTTPS=on
    JkHTTPSIndicator EXTERNAL_TRAFFIC_IS_HTTPS
    

    Might be useful if changing HTTPS would interfere with other modules.