If you are like me and use several different stacks for your projects, you may run into the problem of wanting to run multiple servers on same box/IP and have them receive HTTP requests on the same ports.
Let's say you have a box that hosts PHPApp using (Apache) HTTPD. Now you have the awesome new Java web app JavaApp that you want to host with Tomcat on the same box. You don't want to have to include Tomcat's port numbers in your URLs, but HTTPD is already using the default HTTP(S) ports (80/443). We want requests to
http://javaapp.website.com to go to Tomcat/JavaApp and requests to
http://phpapp.website.com to go to HTTPD/PHPApp. We want HTTPD and Tomcat to respond to requests on the same ports.
TCP only allows one listener per port. If you configure both HTTPD and Tomcat to listen on the same port, when you try to start the second server you will get an error complaining about the port not being available.
To solve this problem, you can pass (proxy) requests from the server listening on the ports you want to the server listening on alternate ports. Because HTTPD's default ports are the ports we want to use, I will use HTTPD to forward requests to Tomcat. I also want only requests sent to
javaapp.website.com to be proxied to Tomcat.
For this tutorial I will assume HTTPD is listening on ports 80 and 443 (HTTPS) and Tomcat is listening on ports 8080 and 8443 (HTTPS).
When you setup a server as a reverse proxy, you are telling that server to act as a middle man between the client and another (origin) server for some requests.
- The proxy server gets an HTTP request.
- If some criteria are met, the proxy server passes (proxies) the request to the origin server.
- The origin server gets the request.
- The origin server creates a response.
- The origin server sends the response to the proxy server.
- The proxy server passes (reverse proxies) the response to the client.
In our case, HTTPD will be our proxy server, Tomcat will be our origin server, and our criteria for passing is if the request was sent to
- HTTPD gets an HTTP request.
- If the host of the request is
javaapp.website.com, HTTPD passes (proxies) the request to Tomcat.
- Tomcat gets the request.
- Tomcat creates a response.
- Tomcat sends the response to HTTPD.
- HTTPD passes (reverse proxies) the response to our client.
From the client's view, a reverse proxy server operates and appears as a normal server.
The first step is to create a virtual host (vhost) to tell HTTPD which requests to proxy and to where.
cd into your HTTPD vhost directory and create a vhost config (EX:
javaapp.conf). The EC2 default is
/etc/httpd/config/vhost/. If you don't have a vhost directory, you may have a single vhosts config file or your virtual hosts may be in your
Create a virtual host for the requests you want to proxy to Tomcat using the
<VirtualHost *:80> ServerName javaapp.website.com ProxyPreserveHost On ProxyPass / http://127.0.0.1:8080/javaapp/ ProxyPassReverse / http://127.0.0.1:8080/javaapp/ </VirtualHost>
This example will proxy all HTTP requests to
javaapp.website.com on port 80 to our local Tomcat server.
http://javapp.website.com/path/page.html will be proxied to
http://127.0.0.1:8080/javapp/path/page.html. Tomcat is running on the same box (127.0.0.1/localhost) and is listening on port 8080, so it will get the request. Tomcat will create the response and send it back to HTTPD. HTTPD will then reverse proxy (pass) the response to the client.
javaapp/ does not have to be included in the origin server URL, but I usually include it so I don't have to include the name of the Java webapp in the URL (
If you get a 503 (service unavailable) error, that means HTTPD is unable to send requests to your Tomcat server. Make sure Tomcat is running, accessible, and accepting requests. You can test with
wget http://127.0.0.1:8080 from your box.
ProxyPreserveHost On ensures the
Host header of the HTTP request remains its original value (
subdomain.website.com) and is not re-written to the proxied host (
There is no setup or configuration needed for Tomcat. Make sure that Tomcat can accept requests from localhost (127.0.0.1). Requests proxied to Tomcat from HTTPD are the same as any normal request Tomcat would receive from a client.
If you have SSL setup, and you want to support proxing HTTPS requests, some additional parameters are required.
<VirtualHost *:80> ServerName javaapp.website.com Redirect permanent / https://javaapp.website.com/ </VirtualHost> <VirtualHost *:443> ServerName javaapp.website.com SSLEngine On SSLCertificateFile certs.www/*.website.com.crt SSLCertificateKeyFile certs.www/*.website.com.key SSLProxyEngine On ProxyPreserveHost On ProxyPass / https://127.0.0.1:8443/javaapp/ ProxyPassReverse / https://127.0.0.1:8443/javaapp/ </VirtualHost>
The first virtual host is optional. It redirects all HTTP requests on port 80 to HTTPS requests on port 443.
The normal SSL directives are used with the addition of
SSLProxyEngine ON which enables the ability to proxy SSL requests. Without this directive you may see the error
SSL Proxy requested for website.com but not enabled.
If your Tomcat server is local like mine, it is not necessary to proxy with an HTTPS request. SSL protects data while in transit. Because the Tomcat server is local, requests proxied from HTTPD to Tomcat do not leave your box and do not need to be secured. However, if your Tomcat ports are open, users will be able to access your server unsecured via that port (
If you do proxy using HTTPS requests, note that (by default) the origin server's SSL certificate is neither validated nor verified. This behavior can be changed using the
SSLProxyVerify directive. This shouldn't be an issue since we are proxying to our own server.