preamble
Everybody who works with ruby on rails more then month knows at least 2 things:
it’s great framework, but can’t handle multiple requests simultaneously due to it still doesn’t use threads.
fast start
As scalability is common issue, rubyonrails site wiki provides full set of solutions:
[http://wiki.rubyonrails.org/#deployment_stacks]
But we as fast solution will use great OpenBSD pf (Packet Filter) that capable to do many cool things.
First issue is standard mongrail cluster that can start several instances of mongrail can only create them on one IP with different ports, and pf can’t distribute requests among different ports on same IP.
Here we can create 2 simple scripts that start and destroy server instances:
# cat start.sh
1 2 3 4 5 6 7 8 9 10 | count=1 for ip in 10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4 10.0.0.5 do mongrel_rails start -e production -d --user myapp --group myapp --chdir /var/www/railsdocs/myapp \ --address ${ip} \ --pid /var/www/railsdocs/myapp/tmp/pids/mongrel.${count}.pid \ --log /var/www/railsdocs/myapp/log/mongrel.${count}.log count=$(($count + 1)) done |
# cat stop.sh
1 2 3 4 5 | for instance in {1..5} do mongrel_rails stop --wait 3 --chdir /var/www/railsdocs/myapp \ --pid /var/www/railsdocs/myapp/tmp/pids/mongrel.${instance}.pid end |
And we need to enable pf:
#/etc/rc.conf.local
1 2 | pf=YES #pflogd_flags= # add more flags, ie. "-s 256" |
add one string to configuration file for load distribution:
#/etc/pf.conf
1 2 | rdr pass log on re0 proto tcp from any to SOME_IP port 80 -> {10.0.0.1, 10.0.0.2, 10.0.0.3, 10.0.0.4, 10.0.0.5 } port 3000 round-robin |
check work with:
# pfctl -s nat
monitor with:
tcpdump -n -e -ttt -i pflog0
for more info on pf:
http://www.openbsd.org/faq/pf/
man pf.conf (especially ‘TRANSLATION’ and ‘POOL OPTIONS’ sections)
Then when you see you need more advanced solution for load distribution you can install haproxy.
Check it with [http://www.openbsd.org/4.5_packages/i386/haproxy-1.3.15.7.tgz-long.html]

Nice writeup!
This is a cool way to use pf to cut out intermediate daemons, but you are losing some of the benefits of that setup. For example if you have nginx or lighttpd do the load balancing you can also have that server serve some static content for you. I have my rails apps setup so that lighty will serve css/js/jpg/png/etc as it is significantly faster than Mongrel serving those files.
If you are using a CDN or simply don’t want that setup of course you’ll need a setup something like this.