Configuring Apache Server Load Balancing for Multiple Virtual Hosts


Another day – another lesson learned. Today I tried to optimize Apache HTTP server configuration in a sense to write less configuration to achieve the same result. Of course I messed up the first few times since I’m not really an admin and don’t have that much experience doing that. Typically relying on short configuration samples and snippets does the trick, but it’s not always the best way to do things. My goals seemed simple enough, I needed to

My backend servers are all Tomcat, I talked about integration between Apache server and Tomcat in my previous posts. The initial version of configuration looked like this

NameVirtualHost *:443
NameVirtualHost *:80

<VirtualHost *:80>
    ServerName server1.domain.com
    Redirect permanent / https://server1.domain.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName server1.domain.com
    SSLProxyEngine On
    KeepAlive On

    <Proxy balancer://wwwCluster>
        BalancerMember ajp://localhost:18009 disablereuse=On route=jvm1
        BalancerMember ajp://localhost:28009 disablereuse=On route=jvm2
    </Proxy>

    ProxyPass / balancer://wwwCluster/ stickysession=JSESSIONID
</VirtualHost>

<VirtualHost *:80>
    ServerName server2.domain.com
    Redirect permanent / https://server2.domain.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName server2.domain.com
    SSLProxyEngine On
    KeepAlive On

    <Proxy balancer://wwwCluster>
        BalancerMember ajp://localhost:18009 disablereuse=On route=jvm1
        BalancerMember ajp://localhost:28009 disablereuse=On route=jvm2
    </Proxy>

    ProxyPass / balancer://wwwCluster/ stickysession=JSESSIONID
</VirtualHost>

And these VirtualHost blocks go on for as many servers as needed. I know it doesn’t look pretty and in fact it’s incorrect since the VirtualHost for SSL connection shouldn’t have a ServerName directive. Not unless you’re using the SNI with mod_gnutls or some specific combination of server and browser like Apache 2.2.12 or later and Mozilla Firefox 2.0 or later. In my environment it did work and so this was used for a while. The first improvement on the configuration that I attempted looked like this:

NameVirtualHost *:80

<VirtualHost *:80>
    ServerName server1.domain.com
    Redirect permanent / https://server1.domain.com/
</VirtualHost>

<VirtualHost *:80>
    ServerName server2.domain.com
    Redirect permanent / https://server2.domain.com/
</VirtualHost>

KeepAlive On

<Proxy balancer://wwwCluster>
    BalancerMember ajp://localhost:18009 route=jvm1
    BalancerMember ajp://localhost:28009 route=jvm2
</Proxy>

NameVirtualHost *:443

<VirtualHost *:443>
    ProxyPass / balancer://wwwCluster/ stickysession=JSESSIONID
</VirtualHost>

At first it semed ok, but then I noticed that it produced a strange side-effect. The balancer worked, but the redirect from HTTP to HTTPS didn’t. Therefore this configuration was not acceptable. Thinking about it some more I realized that I don’t actually need to know the name of the host when redirecting it to my backend server because in my case it will process the Host header and provide the appropriate result. Googling for the redirection to HTTPS alternative I found this page which suggests that Apache’s RewriteEngine could be used to achieve this result. So here’s my final configuration that does the redirect to HTTPS, load balancer’s sticky sessions are functioning properly and everything gets redirected to one of the backend servers chosen by the balancer regardless of the hostname that was used to access it. In other words it works the way I need it to.

NameVirtualHost *:80

<VirtualHost *:80>
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>

ProxyPass / balancer://wwwCluster/ stickysession=JSESSIONID

<Proxy balancer://wwwCluster>
    BalancerMember ajp://localhost:18009 route=jvm1
    BalancerMember ajp://localhost:28009 route=jvm2
</Proxy>

NameVirtualHost *:443

<VirtualHost *:443>
    SSLEngine on
</VirtualHost>

And if you’re using Apache server with PHP rather than JAVA I found this article to be a good read on setting up load balancer with sticky sessions for PHP.