Search code examples
apachetomcatreverse-proxyvirtualhost

Removing Tomcat application context from URL using Apache HTTPD reverse proxy


We are trying to eliminate application context from the URL, but it doesn't work. The Apache web server is fronting the Tomcat server running the Java applications, and Apache virtual host is presented below:

<VirtualHost *:443>
   ServerName                          my.domain.com

   SSLEngine on
   SSLCertificateFile /etc/ssl/certs/some.cer
   SSLCertificateKeyFile /etc/ssl/certs/some.key
   SSLCertificateChainFile /etc/ssl/certs/someother.cer

   ProxyPreserveHost on
   Header edit Set-Cookie ^(.*)$ $1;Secure;SameSite=None

   RewriteEngine on
   RewriteCond %{REQUEST_URI} ^/$
   RewriteRule (.*) /app1/ [R=301]

   ProxyPass            /app1/    ajp://192.168.1.123:9101/app1/
   ProxyPassReverse     /app1/    ajp://192.168.1.123:9101/app1/

</VirtualHost>

Multiple applications are deployed via Tomcat Manager, and every application has a dedicated subdomain. We do not want to change the application context to ROOT.

What should be done to prevent application context from appearing in the URL? For example, we want to access the application via my.domain.com instead of my.domain.com/app1. Removing the path from ProxyPass/ProxyPassReverse didn't help.

The solution with rewrite mode that redirects my.domain.com to my.domain.com/app1 is not applicable because the goal is to prevent context appearance (app1) in any case.


Solution

  • "We do not want to change the application context to ROOT": I am afraid that is what you need to do. To correctly generate hyperlinks servlet applications need HttpServletRequest#getContextPath() to return the correct value. Therefore you:

    • either deploy each application in the root context of their own virtual host. This requires you to change the server.xml file to contain:

      <Engine name="Catalina" defaultHost="app1.example.com">
          <Host name="app1.example.com" appBase="webapps/app1.example.com">
          ...
          </Host>
          <Host name="app2.example.com" appBase="webapps/app2.example.com">
          ...
          </Host>
      </Engine>
      

      and deploy the first application as webapps/app1.example.com/ROOT.war, etc.

    • or write a Valve or Filter that wraps the HttpServletRequest and returns the empty "" as context path.

    Since the first solution is easy to deploy, I don't know any Valve nor Filter that implements the second solution.