Apache SSL Clustering with a Basic Load Balancer
Recently I had a bit of a conundrum – I wanted to offer web-based FTP access to my friends who host on my personal cluster but I didn’t want to run a web server on that centralized machine. (disclosure: I have a vmForge VDC from ipHouse so I can rapidly prototype as needed)
Long story short, I decided to use relayd to answer on the outside interface for port 80 on the IP assigned to the file-server, and use phpWebFTP (looks ugly, works well) on my webcluster. I, however, wanted to use SSL for this server, which brought up its own challenge. How do I tell my Apache front-ends to serve up a different cert for this IP address. After some experimentation, I discovered the right process.
First, a little about SSL. SSL uses DNS for validation; the Common Name (CN) of a certificate has to match the machine that you’re connecting to. The certificate is exchanged upon the connection, and SSL keys negotiated before the client can make requests. However, named based virtual hosting relies on the client requests what site it wants after it connects, so named based virtual hosting does not work with SSL. Well, you can have one cert, but not multiple ones; every site would be served the same certificate, and that would lead to big fat warnings. So if you want to avoid errors, you have to use IP-based virtual hosting. You can renumber at will, or use TCP relaying or port forwarding, but each certificate needs its own IP. (Note: There are hostname extensions to TLS, but I’m unfamiliar with how they are implemented in Apache, I’ll look into that someday)
The best way to do SSL clustering is to offload SSL processing on to your load balancer, and not worry about the backend servers. However, some firewall/load balancers can’t to do this *cough* pfSense *cough* without adding packages that are outside of the user interface. I could add pound via the ports system, but that’s something that I would have to manually track, and defeats the point of having a firewall appliance. If I wanted to go that far, I would just run my firewall as a FreeBSD server, and do everything by hand. I don’t wan to go that far.
First, I had to add another private network to my firewall. I was using 172.16.0.0/24 for my internal machines. Now I added 172.30.0.0/16. That way, I could have a scheme of 172.30.1.1-4 for SSL site 1, 172.30.2.1-4 for SSL site 2, 172.30.3.1-4 for SSL site 3, etc on my front ends.
I added an alias on each Front end for 172.30.1.1, 172.30.1.2, 172.30.1.3, 172.30.1.4 with a netmask of 255.255.0.0.
I then added an IP-based virtual host for my sites. All of my configurations are on my cluster’s file-server, and I didn’t want to set them up individually on each front-end. So I had to figure out a scheme that would produce one valid configuration that works on every server.
Apache loves wildcards, so I was a bit surprised, but ultimately relieved, that using:
<VirtualHost 172.30.1.*:443> didn’t work.
It then occurred to me that Apache has no idea what IP addresses the machine has on it, it just want’s to know which ones it can possibly answer for. Add that to the face that you can have multiple IPs in the same <VirtualHost > and:
<VirtualHost 172.30.1.1:443 172.30.1.2:443 172.30.1.3:443 172.30.1.4:443 >
Works just fine!
I added VirtualHosts for Port 80, set up my front-ends as well so things would are consistent.
Then it was a matter of configuring pfSense to do load balancing, and set up the firewall rules to allow the traffic through. Voila!
So if you have a simple load balancer, you can have Apache handle the SSL in a few short steps (/sarcasm)