Tomas Babic Tomas Babic - 2 months ago 15
Apache Configuration Question

Thymeleaf prepends app context to urls for app behind apache proxy

so I have a bit of a problem with how urls are generated inside my web app.

I have my 'demo' springboot app deployed on my server as 'demo.war' (which expodes to a 'demo' folder). I also have an apache subdomain configured to map demo.myserver.com to the correct context on tomcat:

<VirtualHost *:80>
ServerAdmin admin@myserver.com
ServerName demo.myserver.com

ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / ajp://localhost:8009/demo/
ProxyPassReverse / ajp://localhost:8009/demo/
</VirtualHost>


so far so good. When I go to the http://demo.myserver.com it will pass to the 'demo' context in the tomcat and the page loads. The problem is in how the context-relative URLs in the page are created. The final relevant generated HTML looks like this:

<form action="/demo/loadDataSet" method="get">
<button type="submit">Load next dataset</button>
</form>


The thymeleaf template bit looks like this:

<form th:action="@{/loadDataSet}" method="get">
<button type="submit">Load next data set</button>
</form>


Once I click on such button the URL used is http://demo.myserver.com/demo/loadDataSet which fails with 404 because there is no mapping for the 'demo' context in my 'demo' subdomain. What I would like to know is what to do to generate the html so it looks like this:

<form action="/loadDataSet" method="get">
<button type="submit">Load next dataset</button>
</form>


Thanks guys

Answer

So I had to look into it a bit deeper myself.

Here is the configuration for the apache I came up with:

<VirtualHost *:80>
  ServerAdmin admin@myserver.com
  ServerName demo.myserver.com

  ProxyRequests Off
  <Proxy *>
    Order deny,allow
    Allow from all
  </Proxy>    
  ProxyPreserveHost On
  <Location />
    ProxyPass ajp://localhost:8009/demo/
    ProxyPassReverse ajp://localhost:8009/demo/
    SetOutputFilter INFLATE;proxy-html;DEFLATE
    ProxyHTMLURLMap /demo/ /
    ProxyPassReverseCookiePath /demo/ /
  </Location>
</VirtualHost>

The key here was the line with ProxyHTMLURLMap which takes all references of /demo/ in the HTML passed through and replaces it with /. The ProxyHTMLURLMap can only be withing the <Location> tag where the / is not marking closing of the tag but the path/context to map. In my case the root in the demo subdomain.

Also there was a problem with the configuration of the proxy_html module. For whatever reason the proxy_html.conf was missing so I had to create it myself and to add this inside:

# Here's the declaration for W3C HTML 4.01 and XHTML 1.0
ProxyHTMLLinks  a       href
ProxyHTMLLinks  area        href
ProxyHTMLLinks  link        href
ProxyHTMLLinks  img     src longdesc usemap
ProxyHTMLLinks  object      classid codebase data usemap
ProxyHTMLLinks  q       cite
ProxyHTMLLinks  blockquote  cite
ProxyHTMLLinks  ins     cite
ProxyHTMLLinks  del     cite
ProxyHTMLLinks  form        action
ProxyHTMLLinks  input       src usemap
ProxyHTMLLinks  head        profile
ProxyHTMLLinks  base        href
ProxyHTMLLinks  script      src for
# To support scripting events (with ProxyHTMLExtended On),
# you'll need to declare them too.
ProxyHTMLEvents onclick ondblclick onmousedown onmouseup \
    onmouseover onmousemove onmouseout onkeypress \
    onkeydown onkeyup onfocus onblur onload \
    onunload onsubmit onreset onselect onchange

I have used samples from here, here and here while I was trying the solution out. Hope it helps to someone else as well.

Comments