Note: Making a reverse proxy with nginx is much more straightforward.
A reverse proxy Show archive.org snapshot is a "man in the middle" server that tunnels requests to another server. You can use for things like:
The following describes various Apache 2.4+ VHost directives to reverse-proxy an application that does not want to be reverse-proxied. The example we'll use is a proxy that responds to http://public-host/public-path
and secretly tunnels all requests to http://internal-domain/internal-path
.
For this to work you need the following Apache modules:
headers
substitute
proxy
proxy_http
filter
ssl
The basic VHost setup looks like this:
<VirtualHost *:80>
ServerName public-host
ProxyPass /public-path/ http://internal-host/internal-path/
ProxyPassReverse /public-path/ /private-path/
</VirtualHost>
In the block above, ProxyPass
will setup the reverse proxy.
ProxyPassReverse
will make Apache rewrite 302 redirects like Location: /private-path/foo
to Location: /public-path/foo
.
If you're tunneling to a server that's on HTTPs, you need to use SSLProxyEngine on
:
ProxyPass /public-path/ https://internal-host/internal-path/
SSLProxyEngine on
Note that it doesn't make your proxy available over https://
, it just makes sure that it can fetch from HTTPS internally. You've basically built your custom
SSL-stripping MITM attack server
Show archive.org snapshot
.
If your proxy server should be accessible over HTTPS, use your regular Apache directives (SSLEngine
and friends) for this.
If the internal web app is hard-wiring cookie paths or domains, you need to rewrite those.
You can do this with the following directives:
ProxyPassReverseCookiePath /internal-path/ /public-path/
ProxyPassReverseCookieDomain internal-domain public-domain
If you are changing paths (/internal-path/foo
to /public-path/foo
) /while proxying, the proxied app will probably be broken:
href
s point to the wrong URLbackground-image: url(/internal-path/wallpaper.png)
will be breakThe solution to this involves grepping and replacing all proxied text content. You also need to disable compression so you can find/replace text in the response. All of this is a little screwed up and might have unintended side effects, so make sure you really, absolutely, positively need to change the path while reverse-proxying. If you have control over the internal web application, prefer to deploy it to the same path that you expose publicly.
So anyway, here goes nothing:
# Disable compression
RequestHeader unset Accept-Encoding
Substitute "s|/internal-path/|/public-path/|n"
FilterDeclare NEWPATHS
FilterProvider NEWPATHS SUBSTITUTE "%{Content_Type} =~ m|^text/html|"
FilterProvider NEWPATHS SUBSTITUTE "%{Content_Type} =~ m|^text/css|"
FilterProvider NEWPATHS SUBSTITUTE "%{Content_Type} =~ m|^text/javascript|"
FilterProvider NEWPATHS SUBSTITUTE "%{Content_Type} =~ m|^application/javascript|"
FilterChain NEWPATHS
Note that code above isn't aware of HTML or CSS in any way, it does a brute find-and-replace. You can now no longer use the string /internal-path/
anywhere in your views.
Also note that the FilterProvider
syntax has changed in recent Apache versions, so make sure your Apache version (apache2ctl -v
) is 2.4 or higher.