Short Story
Gah! I wish the developers who did admin interfaces would expose a "webroot=/myAppAppearsHere" option, or make all links relative.

Long Story

I have an admin portal for a customer that is basically an apache mod_auth login and then a series of links on to back-end admin pages like so;


and then a bunch of links like so

https://portal.mysite.com/monitoring   -> https://nagios.localdomain/nagios
https://portal.mysite.com/munin     -> https://munin.localdomain/nagios
https://portal.mysite.com/bacukups     -> https://backups.localdomain/backups

However there are a couple of applications are that really not happy with being reverse proxied to a subdirectory, for example chef-server-webui and the logstash web interface.

ProxyPassReverse will remap the headers, but all the internal absolute URLS need to be altered and if there is no option for this in the app config, then this has to be coerced into the HTML response.

The obvious tactic is to create subdomains, or wildcard subdomains to map to these apps like so;

https://chef.mysite.com/   -> https://chefserver.localdomain:4040/
https://logstash.mysite.com/   -> https://logstash.localdomain/
https://*.mysite.com/   -> https://($1).localdomain/

But unfortunately I am not in control of the administration of the domain, and obtaining these additions is possible but a pain. (but I would prefer a solution that doesn't require some 3rd party to be involved for each new link) (I am aware a wild-card would solve this, but I am interested in seeing what HTTP and apache based alternatives there are ... for learning etc ;-)

So I have moved to using the Apache2::ModProxyPerlHtml which is similar to mod_proxy_html, and allows dynamic remapping of strings in the docs. This actually does work with some combination of LocationMatch and ProxyHTMLRewrite I can even get the javascript to play nice. However it is a massive ball-ache to do each one, especially for any non web 1.0 apps.

For example the following almost fixes logstash to work correctly under /logstash;

<LocationMatch "^/logstash/">

    RequestHeader   unset   Accept-Encoding
    PerlSetVar ProxyHTMLVerbose "On"
    PerlInputFilterHandler Apache2::ModProxyPerlHtml
    PerlOutputFilterHandler Apache2::ModProxyPerlHtml
    SetHandler perl-script
    PerlAddVar ProxyHTMLRewrite "/style.css /logstash/style.css"
    PerlAddVar ProxyHTMLRewrite "/css/smoothness/jquery-ui-1.8.5.custom.css /logstash/css/smoothness/jquery-ui-1.8.5.custom.css"
    PerlAddVar ProxyHTMLRewrite "/js/jquery-1.6.1.min.js /logstash/js/jquery-1.6.1.min.js"
    PerlAddVar ProxyHTMLRewrite "action='/search' action='/logstash/search'"
    PerlAddVar ProxyHTMLRewrite "/js/jquery-ui-1.8.13.min.js /logstash/js/jquery-ui-1.8.13.min.js"
    PerlAddVar ProxyHTMLRewrite "/media/throbber.gif /logstash/media/throbber.gif"

    PerlAddVar ProxyHTMLRewrite "/api/search /logstash/api/search"
    PerlAddVar ProxyHTMLRewrite "/api/histogram /logstash/api/histogram"


But its extremely hit and miss, and you can't just wildcard the URL swap, because there is loads of JSON and javascript that gets mangled.

I was thinking of some sort of cookie or querystring var that tracked the current Proxy Backend, so apache could dynamically redirect the request onto the correct backend.. Something like this;

https://admin.mysite.com/?request-proxy=chef -> https://chefserver.localdomain:4040/
https://admin.mysite.com/?request-proxy=logstash  -> https://logstash.localdomain/

And basically, as apache gets last look at all the server HTTP content, it could dynamically tag urls with the additional query vars &request-proxy=logstash. However I am thinking that would suffer from the same problem as the ModProxyPerlHtml/mod_proxy_html solution in that it would never work everywhere, especially in apps where some javascript was used to bejiggle with the QUERY params client side.

I guess a cookie would almost work, in that you could Proxy based on some passed cookie value say "request-proxy=logstash", however this would suffer a problem if you had 2 tabs open to the site as they would probably write over each others cookies.

I know that some apps just take some sort of brute force approach and wrap the whole proxied request in re-baked html such as the Netscreen SA-3000.

Anyway, so are there any apache modules that implement either of these strategies, or somehow side step writing matching rules for each proxied site.?

  1. ps I am aware of lemonldap, but I didn't get far without having to dive down into perl code. Although it looks cool and I will take another look in future.
  2. I am starting to suspect that time-wise I might as well just spend the time remapping these HTML pages with ModProxyPerlHtml, because there won't be a one-size fits all solution.
  • mod_substitute is now a standard module, so I do remapping on the fly with that. – Tom H Apr 2 '12 at 5:11
  • Hi Tom, we have here a comparable situation and after some tests with Nginx we are using now Varnish for this. The reverse proxy is more or less a gateway to different back-end systems. We are doing the differentiation based on the request URL. But we do not rewrite URLs. – Jens Bradler Apr 25 '12 at 7:52
  • BTW: We had similar trouble with logstash 1.0.9, but 1.1.13 seems to have fixed these problems and uses only relative links. – Hans-Peter Störr Jun 27 '13 at 17:18

mod_substitute does the job very well;

Summary: mod_substitute provides a mechanism to perform both regular expression and fixed string substitutions on response bodies.

It just takes a bit of time working through the mapping rules.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.