Deploying Rails with Pound in Front of Mongrel, Lighttpd, and Apache

It seems that the Rails deployment dilemma is finally getting the care that it desperately needed to make the whole situation less of a pain in the neck. For a while there, everyone was hanging on the edge or their seats, hoping that Apache developers would fix Apache’s FastCGI interface that had fallen out of maintainence. While waiting for that, many people flocked to Lighttpd as a promising faster/lighter alternative to Apache that seemed to have its FastCGI interface under control.

Meanwhile, development of an alternative to WEBrick was under way, by a guy named Zed Shaw, called Mongrel. It seems Zed just got fed up and decided to change the Rails deployment world with his own bare hands. This is good news for all of us and the best thing about Zed is how much he cares about getting a situation together that works for everyone. (Also, if you ever need help with Mongrel, Zed is always right there with the answer.) So, this seemingly simple little pure HTTP web server has turned out to be much more usefull than anticipated. With the introduction of the mongrel_cluster gem, serving Rails applications with a small pack of Mongrel processes and a load balancer is a snap.

Software load balancers that people are using include Pen, Pound, and Apache2’s mod_proxy_balancer. Recently, on the main Rails blog, there was a post about setting up lighttpd with a single proxy to Pound which in turn served up a cluster of Mongrel processes. In reading the post and its comments I realized there seems to be some confusion about where Pound can exist within a typical deployment setup. A few people commented that with Lighttpd in front of Pound, the value of request.remote_ip was 127.0.0.1 (localhost) or something other then the IP of each external request.

There is no reason that Pound can’t sit out in front of Lighttpd, a pack of Mongrels, or any other web servers waiting to process and respond to requests. Because of the way Pound handles headers, the correct value of request.remote_ip is preserved by the time the request is received by Rails. In any case, the Pound docs send the vibe that the intention is to have Pound in front of other servers. Here’s a bit from the latest Pound README that talks about what Pound is and how it can be used:

Pound-2.0.9/README

a reverse-proxy: it passes requests from client browsers to one or more back-end servers.

a load balancer: it will distribute the requests from the client browsers among several back-end servers, while keeping session information.

an SSL wrapper: Pound will decrypt HTTPS requests from client browsers and pass them as plain HTTP to the back-end servers.

an HTTP/HTTPS sanitizer: Pound will verify requests for correctness and accept only well-formed ones.

a fail over-server: should a back-end server fail, Pound will take note of the fact and stop passing requests to it until it recovers.

a request redirector: requests may be distributed among servers according to the requested URL.

It’s number six above that give Pound its flexibility in terms of serving different requests to different back-end web servers. So, on with a simple demo of a Pound setup that passes requests back to a cluster of Mongrels, an Apache server, and a Lighttpd server.

Check out my full demonstration of how to set up Pound in front of your other servers, including a cluster of Mongrel processes serving Rails, here: