Thursday, November 22, 2018

Using Apache 2.4 Reverse Proxy to some (but not all) Tomcat/JavaEE Applications

Usually if you have a couple of Tomcat WAR's (Java WEB applications) deployed on a Tomcat Servlet Container, you a couple of options when exposing those applications through an Apache (or NGINX) http server.

Server Setup is laid out in the following pic:

Server Layout


For the sake of this discussion, let's assume we have these WAR applications deployed in Tomcat server (besides ROOT and manager default applications):

* users.war     -> tomcat context /users
* webapp.war    -> tomcat context /webapp
* discovery.war -> tomcat context /discovery
* bingo.war     -> tomcat context /bingo
* clubs.war     -> tomcat context /clubs
  

Option 1)

Just do a full reverse proxy from the Apache Server to the Tomcat Server (you could either use AJP or HTTP connectors for that purpose).

Apache Configuration will be something like this:

    <Location /tomcat/>
        ProxyPass ajp://192.168.0.2:8080/
        ProxyPassReverse https://example.com/tomcat/
    </Location>

This is very easy to use and setup. It just takes to add these lines to a virtual host and done!

You could access the tomcat Applications to the following URLs:

* http://example.com/tomcat/users
http://example.com/tomcat/webapp
http://example.com/tomcat/discovery
http://example.com/tomcat/bingo
http://example.com/tomcat/clubs

The problem with this approach is:

a. You have access to ALL APPLICATIONS (even if you don't want to)
b. You have access to default applications (if they're not removed) such as Tomcat's ROOT and Manager.

Option 2)

Do one reverse proxy location for each application you want to expose. Let's say you want to expose `users`, `webapp` and `clubs`. Your configuration will be something like this:

    <Location /tomcat/users/>
        ProxyPass ajp://192.168.0.2:8080/users/
        ProxyPassReverse https://example.com/tomcat/users/
    </Location>
    <Location /tomcat/webapp/>
        ProxyPass ajp://192.168.0.2:8080/webapps/
        ProxyPassReverse https://example.com/tomcat/webapp/
    </Location>
    <Location /tomcat/clubs/>
        ProxyPass ajp://192.168.0.2:8080/clubs/
        ProxyPassReverse https://example.com/tomcat/clubs/
    </Location>

The problem with this approach is obvious:

a. If you deployed 25 WARs in your tomcat and want to expose 18 of them, your Apache configuration will grow, and will become harder to maintain.
b. COPY+PASTE error might occur more frequently when adding new applications
c. If your Location sections contains more configuration options (RequestHeader directives, Require, Auth Type) then your COPY+PASTE gets bigger every time, and if you need to change/add something, you will need to do it in every single configuration you have done before.


Option 3)

My favorite option nowadays.

If you want the three same applications exposed, you can use LocationMatch and ProxyPassMatch directives to get the best of both previous options:

    <LocationMatch "^/tomcat/(?<apiurl>(users|webapp|clubs)/.*)">
        ProxyPassMatch ajp://192.168.0.2:8009/$1
    </LocationMatch>

You use a regular expression to filter what domains will go through to tomcat server, and you keep it only in one configuration.