Running the IdP on Jetty behind Apache httpd

This is a quick guide for configuring Jetty to run behind an Apache httpd front end. While typically not necessary, you may need to do this if you are using Remote User Authentication or External Authentication in conjunction with a product that is not Java-based. There may be other use cases as well.

This method works by running Jetty on the loopback interface (localhost) and configuring Apache to proxy requests to it via mod_proxy_http. While this is functionally similar to proxying to Tomcat via AJP, we can't take the same approach here because Jetty no longer supports AJP.

This documentation assumes you are running Apache httpd v2.2 and Jetty 9.2. Make sure mod_proxy_http is installed as well; it should be there by default on most packaged Apache distributions.

Step-by-step guide

  1. Configure a Jetty HTTP connector on the loopback interface. This is done in jetty.xml:

    <Call name="addConnector">
      <Arg>
        <New class="org.eclipse.jetty.server.ServerConnector">
          <Arg name="server"><Ref refid="Server" /></Arg>
          <Arg name="factories">
            <Array type="org.eclipse.jetty.server.ConnectionFactory">
              <Item>
                <New class="org.eclipse.jetty.server.HttpConnectionFactory">
                  <Arg name="config"><Ref refid="httpConfig" /></Arg>
                </New>
              </Item>
            </Array>
          </Arg>
          <Set name="host"><Property name="jetty.nonhttps.host" default="localhost" /></Set>
          <Set name="port"><Property name="jetty.nonhttps.port" default="8080" /></Set>
          <Set name="idleTimeout"><Property name="http.timeout" default="30000" /></Set>
          <Set name="soLingerTime"><Property name="http.soLingerTime" default="-1"/></Set>
        </New>
      </Arg>
    </Call>

    Make sure the connector is configured to only listen on the loopback interface (localhost). It must not be exposed to external hosts!

    This is the only connector that is needed; all others can safely be disabled.

  2. Note that the connector we've configured is using plain HTTP. The request comes into Apache over HTTPS, but we're forwarding it to Jetty via HTTP over the loopback interface. For this to work, Jetty needs to accept the X-Forwarded-Proto HTTP header, which by default, it does not. Enable this by editing jetty.xml and adding the following within the <New id="httpConfig" ..> section:

    <Call name="addCustomizer">
      <Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
    </Call>
  3. Configure Apache httpd to proxy requests to /idp to Jetty. In httpd.conf:

    <IfModule mod_proxy.c>
        ProxyPreserveHost On
        RequestHeader set X-Forwarded-Proto "https"
        RequestHeader set X-Forwarded-Port 443
        ProxyPass /idp http://localhost:8080/idp
        ProxyPassReverse /idp http://localhost:8080/idp
    </IfModule>

    The first two lines tell Apache to preserve the host and scheme when proxying the request to Jetty.

  4. Restart httpd and Jetty, and make sure all works as expected.

Considerations

When running command-line utilities such as aacli and reload-service, you'll need to explicitly specify the loopback URL on the command line. For example:

./aacli.sh --url=http://localhost:8080 --principal=AB123 --requester=https://wiki.shibboleth.net/shibboleth