Mass virtual hosting security tip when using a reverse proxy to connect to other servers

Thu, May 02, 2013 at 8:05PM

Yesterday, I realized there was a security flaw in the setup of our mass virtual hosting configuration in the Nginx web server.   Mass virtual hosting allows me to map host names to their respective directories on the filesystem without having to make a duplicate configuration for every domain.  

To do mass virtual hosting in Nginx, you can use a wildcard server name like "server_name www.*;" to match all domains like,, etc.  Then I use url rewrites with regular expressions to map all the urls for my application and to set the root path for each host name.

When it gets down to the part where Nginx calls Railo, I had it setup to use this configuration line in nginx.conf:

proxy_pass http://$host:8888$uri$is_args$args;

The problem with doing that is that it will also match for domains that don't exist if a user sends false dns information to the server.  Some robots were doing this to attempt to do a denial of service attack on remote domains such as the FBI and other servers.   Because of the non-standard port, 8888, these connections were timing out instead of hitting the home page.  Even though it wasn't letting them hitting the fbi, it was still a security flaw and allowed some abuse of our server.

I realized that it is more correct to use a local ip address in the Nginx proxy_pass:


Then you set some proxy headers in Nginx so Railo can read the original host name and remote ip address.

proxy_set_header HTTP_HOST $host;
proxy_set_header REMOTE_ADDR $remote_addr;

Also in /opt/railo/tomcat/conf/server.xml, I needed to set the host name to be a matching static ip like this:

<Host name="" appBase="webapps" unpackWARs="true" autoDeploy="true" ><Context path="" docBase="/home/path/to/root" /></Host>

You might also need to change the engine to use as the default host.

<Engine name="Catalina" defaultHost="">

After restarting Nginx and Railo, it still doesn't automatically work.  

In Railo, cgi.http_host will equal, which means you can't use that variable to map the request to a specific host name anymore.  To access the proxy header, you must use code like this in CFML:

if(structkeyexists(request.httpRequestData.headers, 'http_host')){
if(structkeyexists(request.httpRequestData.headers, 'remote_addr')){

Since my application was already using duplicate of the cgi scope everywhere, I only had to change this in one place to switch from using name based virtual host to a static ip.

These small changes allowed me to continue using mass virtual hosting configuration while making it more secure. 

Bookmark & Share