Lately I’ve fallen in love with a couple of fairly simple but powerful technologies: haproxy and WSGI (web server gateway interface). While the latter is more of a specification (PEP 333) the concepts it puts forth have made my life significantly easier. In combination, the two of them make for a powerful combination for serving web applications of all kinds and colors.
HAProxy is a robust, reliable piece of load balancing software that’s very easy to get started with, For the uninitiated, load balancing is a common means of distributing the load of a number of inbound requests across a pool of processes, machines, clusters and so on. Whenever you hit any web site of non-trivial size, your HTTP requests are invariably transparently proxied through a load balancer to a pool of web machines.
I started looking into haproxy when I began to move Urlenco.de away from my franken-setup of Lighttpd/FastCGI/Mono/ASP.NET to a pure Python stack. After poking around some articles about haproxy I discovered it can be used for virtual hosts as well as simple load balancing. Using a haproxy’s ACLs feature (see Section 7 in the configuration.txt), you can redirect requests to one backend or another. While my “virtual hosting” with haproxy is using the ability to inspect the HTTP headers of inbound requests, you can use a number of different criterion to determine the right backend for serving a request: url matching, request method matching (GET/POST), protocol matching (haproxy can load balance any kind of TCP connection) and so on.
WSGI (pronounced: whiskey) comes into play on the backend side of haproxy, using the eventlet.wsgi module which provides a WSGI interface I can build web applications very quickly, test them and deploy them. When deployed, I can run them as “nobody” in userspace on the server, binding to some higher numbered port (i.e. 8080) and haproxy will do the work routing to the appropriate WSGI process.
Below is a simple haproxy configuration that I’m using to run Urlenco.de and
a site for my wedding and many more as soon as I finish them. The section to note is frontend http-in
in which the ACLs are defined for the different virtually hosted domains and the conditionals for selecting a backend based on those ACLs.
global
maxconn 20000
ulimit-n 16384
log 127.0.0.1 local0
uid 200
gid 200
chroot /var/empty
nbproc 4
daemon
defaults
log global
mode http
option httplog
option dontlognull
retries 3
option redispatch
maxconn 2000
contimeout 5000
clitimeout 50000
srvtimeout 50000
frontend http-in
bind *:80
acl is_urlencode hdr_end(host) -i urlenco.de
acl is_wedding hdr_end(host) -i erinandtylerswedding.com
use_backend urlencode if is_urlencode
use_backend wedding if is_wedding
default_backend urlencode
backend urlencode
balance roundrobin
cookie SERVERID insert nocache indirect
option httpchk HEAD /check.txt HTTP/1.0
option httpclose
option forwardfor
server Local 127.0.0.1:8181 cookie Local
backend wedding
balance roundrobin
cookie SERVERID insert nocache indirect
option httpchk HEAD /check.txt HTTP/1.0
option httpclose
option forwardfor
server Local 127.0.0.1:8081 cookie Local