Apache URL rewriting in reverse proxy
Solution 1
This is how I got it to work. As well as the changes as per my comment to my original question, I needed to exclude .js
and .css
from the rule that added a trailing slash.
<VirtualHost *:80>
ServerAdmin admin@localhost
ServerName mydomain.com
ServerAlias www.mydomain.com
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
RewriteLog ${APACHE_LOG_DIR}/rewrite.log
RewriteLogLevel 9
Alias /images/ "/var/www/images/"
RewriteEngine On
# rewrite rule to prevent proxy exploit
RewriteCond %{REQUEST_URI} !^$
RewriteCond %{REQUEST_URI} !^/
RewriteRule .* - [R=400,L]
# consolidate non-www requests onto the www subdomain
RewriteCond %{HTTP_HOST} ^yourdomain\.com$
RewriteRule ^(.*) http://www.yourdomain.com/$1 [R=301,L]
# Add a trailing slash to the URL (ignoring images, CSS and JavaScript)
RewriteCond %{REQUEST_URI} !^/(images)(.*)$
RewriteCond %{REQUEST_URI} !^/(.*)(.js|.css)$
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://%{HTTP_HOST}$1/ [R=301,L]
# proxy to the Jellyfish server (ignoring images)
RewriteCond %{REQUEST_URI} !^/(images)(.*)$
RewriteRule ^(/.*)$ http://app-server:8181/jellyfish$1 [P]
ProxyPassReverse / http://app-server:8181/jellyfish/
# suppress mod_security rules that were giving false positives
SecRuleRemoveById 981059 981060
<Directory "/var/www/images">
Options Indexes MultiViews FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
Solution 2
Have you tried:
ProxyPassMatch ^/(.*) http://granny-server:8181/$1
ProxyPassReverse / http://granny-server:8181
Or even more simply:
ProxyPass / http://granny-server:8181/
ProxyPassReverse / http://granny-server:8181/
I wrote up how I deal with Apache reverse proxying and Tomcat over here if you want to compare/contrast what you setup with what I use.
You might want to add this to add a trailing slash to the URL:
# Settings for adding a trailing slash to the URL
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/$
RewriteRule ^(.*)$ http://%{HTTP_HOST}$1/ [R=301,L]
Related videos on Youtube
![Jeremy Gooch](https://i.stack.imgur.com/HO7g8.jpg?s=256&g=1)
Jeremy Gooch
Updated on September 18, 2022Comments
-
Jeremy Gooch almost 2 years
I'm deploying Apache in front of a Karaf-hosted application (Apache and Karaf are on separate servers). I want Apache to operate as a reverse proxy and also to hide part of the URL.
The URL to get the log-in page of the application directly from the app server is
http://app-server:8181/jellyfish
. Pages are served by the Jetty instance running within Karaf. Of course, this behaviour would usually be blocked by the firewall for everything except the reverse proxy server.With the firewall off, if you hit this URL then Jetty loads the log-in page. The browser's address bar correctly changes to
http://app-server:8181/jellyfish/login?0
and everything works.What I want is for
http://web-server
(i.e. from the root) to map to Jetty on the app server with the name of the app (jellyfish
) suppressed. e.g. The browser would change to showhttp://web-server/login?0
in the address bar and all subsequent URLs and content would be served with the web-server's domain and without thejellyfish
clutter.I can get Apache to operate as a simple reverse proxy, using the following config (snippet):-
ProxyPass /jellyfish http://app-server:8181/jellyfish ProxyPassReverse / http://app-server:8181/
...but this requires the browser's URL to contain
jellyfish
and going to the root URL (http://web-server
) gives a 404 Not Found.I've spent a lot of time trying to use
mod_rewrite
with and without its[P]
flag to get around this, but without success. I then tried theProxyPassMatch
directive, but I can't seem to get that quite correct either.Here's the current config, as is loaded into
/etc/apache2/sites-available/
on the web server. Note that there is a locally-hosted images directory. I've also kept the mod_rewrite proxy exploit protection and am suppressing a couple ofmod_security
rules that were giving false positives.<VirtualHost *:80> ServerAdmin admin@drummer-server ServerName drummer-server ErrorLog ${APACHE_LOG_DIR}/error.log LogLevel warn CustomLog ${APACHE_LOG_DIR}/access.log combined Alias /images/ "/var/www/images/" RewriteEngine On RewriteCond %{REQUEST_URI} !^$ RewriteCond %{REQUEST_URI} !^/ RewriteRule .* - [R=400,L] ProxyPass /images ! ProxyPassMatch ^/(.*) http://granny-server:8181/jellyfish/$1 ProxyPassReverse / http://granny-server:8181/jellyfish ProxyPreserveHost On SecRuleRemoveById 981059 981060 <Directory "/var/www/images"> Options Indexes MultiViews FollowSymLinks AllowOverride None Order allow,deny Allow from all </Directory> </VirtualHost>
If I go to
http://web-server
, I get redirected tohttp://web-server/jellyfish/home
but this gives a 404, with a complaint about trying to access/jellyfish/jellyfish/home
- NB the browser's address bar does not contain the double/jellyfish
.HTTP ERROR 404 Problem accessing /jellyfish/jellyfish/home. Reason: Not Found
And, if I go to
http://web-server/login
, I get redirected tohttp://web-server/jellyfish/login?0
but this gives a 404, with a complaint about trying to access/jellyfish/jellyfish/login
.HTTP ERROR 404 Problem accessing /jellyfish/jellyfish/login. Reason: Not Found
So, I'm guessing I'm somehow passing through the rules twice. I am also slightly bemused as to where the
home
bit of the URL comes from in the first example.Can someone point me in the right direction, please?
Thanks, J.
-
Jeremy Gooch over 10 yearsI've made some progress on this, and have now replaced
ProxyPassMatch
with an equivalent usingmod_rewrite
, which addresses the challenge of removingjellyfish
from the URLs. I'm now looking into a number of 404s that then pop up with regard to underlying elements such as Wicket components required by Karaf. Here's a code snippet:# proxy to the Jellyfish server (ignoring images) RewriteCond %{REQUEST_URI} !^/(images)(.*)$ RewriteRule ^(/.*)$ http://app-server:8181/jellyfish$1 [P] ProxyPassReverse / http://app-server:8181/jellyfish/
-
-
Jeremy Gooch over 10 yearsMany thanks for the reply. Unfortunately, this only resolves the straightforward proxying part of the problem. The bit I'm missing is how to remove the word "jellyfish" from visibility in the client's browser address bar, such that
http://web-server
silently gets proxied tohttp://app-server:8181/jellyfish
and back again.