I have several web applications hosted on an AWS server on different ports, e.g.
app1: http://x.x.x.x:8080
app2: http://x.x.x.x:9000
...
I would like to a proxy in front of these apps (apache, nginix etc.) so that all of them can be accessed using port 80. I could think of two aproaches:
Put each app on a different sub-domain and forward based on the sub-domain, e.g
http://app1.mydomain.com --> http://x.x.x.x:8080 http://app2.mydomain.com --> http://x.x.x.x:9000
However in my case, I do not control the creation of subdomains. I have been given on sub-domain and I have to live with that. So this approach does not work.
Use a seperate URL for each app and then rewrite the URL, e.g.
http://mysubdomain.mydomain.com/app1 --> http://x.x.x.x:8080 http://mysubdomain.mydomain.com/app2 --> http://x.x.x.x:9000
However, I am running into an issue with this approach. For example, http://mysubdomain.mydomain.com/app1
correctly returns index.html from the app1, but then that index.html asks for js and css files without the app1 prefix, e.g. it asks for http://mysubdomain.mydomain.com/js/main.js
instead of http://mysubdomain.mydomain.com/app1/js/main.js
. As you can see, the forwarding rule no longer works. Even more confusing is that if my initial request terminates with a slash (http://mysubdomain.mydomain.com/app1/
), then the requests for js and css files is formatted correctly (http://mysubdomain.mydomain.com/app1/js/main.js
). I don't understand this behavior!
Is there any other approach that you can think of? I have heard of host header mapping, but couldn't figure out how it works. I can't imagine that this problem has not been solved!
Edits based on suggestion from @stoned
I have a Web application served from http://x.x.x.x:8080. This URL serves the index.html file which pulls in bunch of CSS and JavaScript files.
Here's my attempt to reverse proxy this app using Apache running at http://www.example.com
:
# Reverse proxy requests for /app1 to http://x.x.x.x:8080
ProxyRequests off
ProxyPass /app1 http://x.x.x.x:8080
ProxyPassReverse /app1 http://x.x.x.x:8080
This does not work when I type http://www.example.com/app1
in my browser (note no slash at the end).
index.html
is served correctlyHowever
index.html
asks for css and js with lines like this:<link rel="stylesheet" href="vendor/bootstrap.min.css"/> <script src="vendor/angular.min.js"></script>
This translates to requests like this with no
app1
imbedded in the URL:http://www.example.com/vendor/bootstrap.min.css http://www.example.com/vendor/angular.min.js
Obviously, the reverse proxy does not know what to do with these!
However, if I add a slash at the end of the URL (
http://www.example.com/app1/
), then the requests are translated correctly:http://www.example.com/app1/vendor/bootstrap.min.css http://www.example.com/app1/vendor/angular.min.js
I don't understand how adding a slash at the end makes the browser behave differently! Anyway, the important point is that I can't expect my users to type a slash at the end. Any thoughts on how to solve this problem?
Solved - Finally!
After bunch of googling I found that a trailing slash is used to indicate that the requested resource is a directory. In such cases the "default" resource from the directory is returned (usually index.html). If a user wrongly requests a directory without a trailing slash, mod_dir (which is normally loaded in Apache installations) adds a trailing slash and does a client-side redirect, fixing the problem.
In my case, http://www.example.com/app1
was not redirecting to http://www.example.com/app1/
(with a trailing slash) because /app1
is not a real directory on the apache server - mod_dir was not detecting this. Hence this URL was being proxied to http://x.x.x.x:8080 as is. While this was correctly returning the index.html, but the subsequent requests were relative to http://www.example.com
and not http://www.example.com/app1
. To fix the problem, I added a rewrite rule to redirect http://www.example.com/app1
to http://www.example.com/app1/
(with a slash). I also changed my reverse proxy rules to only match if I find a trailing slash. See below:
# Fix any request for /app1 to /app1/
RewriteEngine on
RewriteRule ^/app1$ /app1/ [R]
# Reverse proxy requests for /app1/ to http://x.x.x.x:8080/
ProxyRequests off
ProxyPass /app1/ http://x.x.x.x:8080/
ProxyPassReverse /app1/ http://x.x.x.x:8080/