There are a nauseating array of options to choose from when deciding how you’re going to stick your Ruby on Rails application up on a web server. There is no real canonical formula (yet), and depending on your needs, there may be multiple passable options—though none of them are entirely pretty or elegant.
The most common stack for a while was Apache or Lighty using FCGI. The release of Mongrel has completely changed that. Mongrel is in itself a very basic web server, similar to WEBrick. Mongrel is capable of serving up your Rails application over HTTP without FCGI. Unfortunately, it is very limited (can’t host multiple sites, doesn’t have a rewrite library, doesn’t support SSL, etc), so in most cases you’ll have to stick another server out in front of it to handle those things and then proxy Rails requests over to Mongrel. So, the question is, what do you put out in front of Mongrel to proxy requests?
I’m not going to discuss all the options, but if you’re looking for what appears to be (at the moment) a setup that is a breeze to install and will churn out more requests/second than anything else, read on.
One of the downsides to this setup is that the reverse proxy server we will be using, nginx, is a Russian project with almost no English documentation. Although, there seems to be at least two capable Rails developers (1, 2) who are vouching for its speed and stability.
- The Pros: * This setup will probably squeeze out more requests/second out of your Rails app than any other. * It’s fairly simple to setup (if your setup is simple). * It’s very lightweight, using much less memory than most traditional FCGI setups.
- The Cons: * Not many people are using nginx, so you’ll be living on the edge if you choose to do so. * I can only find one case of a Rails developer who is using nginx in a production setup, although he appears to be very happy with it. * The fact that it exists mostly in the nebulous world of the Russian internets means we don’t have a good sense of how secure/stable/tested it is. The lack of a reputation in the English speaking world is a little unsettling.
- nginx – “a high perfomance http and reverse proxy server”
- Mongrel – “a fast HTTP library and server for Ruby that is intended for hosting Ruby web applications of any kind using plain HTTP rather than FastCGI or SCGI.”
- Mongrel_cluster – “a GemPlugin that wrappers the mongrel HTTP server and simplifies the deployment of webapps using a cluster of mongrel servers. Mongrel\_cluster will conveniently configure and control several mongrel servers, or groups of mongrel servers, which are then load balanced using a reverse proxy solution.”
- Ubuntu Server or Debian
- Your Ruby on Rails applications
The final setup should look like this: 1. For every Rails application, you will have 1 Mongrel cluster, each with multiple Mongrel instances (processes). 1. nginx sits in front, accepting connections from clients. 1. If static content is requested, nginx serves it up directly. nginx is capable of serving up static files very quickly. 1. If dynamic content is requested, the request is proxied off to the appropriate Mongrel cluster. 1. One of the processes of the Mongrel cluster receives the request, processes the request through your Rails application, and returns the response to the client.
So, we’ll start with a basic installation of Ubuntu or Debian and end with an awesome Rails stack serving up multiple websites. This isn’t going to be a step by step tutorial, but rather what is hopefully enough hastily patched together tidbits to help you hit the ground running. 1. First, get Ubuntu up and running with a bare bones install. In my case, my VPS provider did this for me. 1. Setup the basic Rails tools you will need on the server such as Subversion, Ruby, ImageMagick, RMagick, MySQL, SSH. A great guide for this can be found over at brainspl.at. If you follow that tutorial, DO NOT INSTALL LIGHTTPD AND FCGI. It is totally unnecessary for our setup. 1. Get your Rails projects onto the server, either via Subversion checkout, Capistrano, or whatever it is you prefer. 1. Setup Mongrel and Mongrel\_cluster. The former tutorial will detail how to setup your Mongrel cluster to start at boot. Unfortunately, this only works on Debian and NOT Ubuntu. You can find a fix here. 1. Make sure your Mongrel cluster works before proceeding. You can connect directly to one of the Mongrel instances that you started up if you don’t have a firewall blocking its port. One of my Rails apps had 2 Mongrel processes listening on ports 5001 and 5002. I connected to http://domain1.com:5001 and the page loaded just fine. If you don’t have this much working, there’s no point in proceeding. 1. Make sure Apache and Lighttpd are not installed on the system, and nothing is using port 80. (`netstat -an | grep 80`) 1. Read this and compile/install nginx. After you follow those directions, there are only three more quick steps: 1. Setup the config file at /usr/local/nginx/conf/nginx.conf. In the brainspl.at tutorial he gives you his sample config file. This demonstrates how to serve up static files with nginx and proxy dynamic requests to Mongrel. This should be enough for most people, unless you are using SSL or need virtual hosting. In which case, you might find these “Typical Configurations” very helpful. Here is my configuration file which uses virtual hosting to serve up requests to the appropriate Mongrel cluster, and only passes dynamic requests to Mongrel while having nginx itself serve up static requests. 1. Create an nginx init.d script. An init.d script is an easy way to start/stop/restart a daemon. It goes in /etc/init.d and commands will typically look like:
/etc/init.d/nginx start
/etc/init.d/nginx stop
To set this up, perform these commands:
wget http://notrocketsurgery.com/files/nginx \
-O /etc/init.d/nginx
chmod 750 /etc/init.d/nginx
This makes it easy to manage nginx. Give it a shot and make sure it’s working! (Disclaimer: I made this init.d script from the /etc/init.d/skeleton file without too much knowledge of what everything meant, so feel free to post corrections/improvements in a comment below)
1. Setup nginx to start at boot.
update-rc.d nginx defaults
This takes the /etc/init.d/nginx script above and makes all the appropriate references to it in the runlevel scripts. Yeah, that wasn’t English to me either the first time I read it. First, read up on what runlevels are. So, what you need is the operating system to call `/etc/init.d/nginx start` and `/etc/init.d/nginx stop` at the appropriate runlevels. That is what the above command does automatically for you! You can read up more in the man page (`man update-rc.d`). Try restarting your server and make sure that both the Mongrel processes and the nginx daemon are still running after you restart. A quick look at `pstree` will verify this.
If those instructions were TOO sparse, please feel free to ask for clarifications by commenting below. I’ll try to answer any questions.
Thanks to Ezra Zygmuntowicz and Alexey Kovyrin for posting so much helpful information on their blogs which pretty much make up almost all the content in this post. Thanks to Zed Shaw for making Mongrel and being a cool guy.




August 27th, 2006 at 06:16 PM If you want, visit my blog in next wef days. I will post there really comprehensive rails deployment schemes information.
August 27th, 2006 at 06:29 PM I can't wait to see it, Alexey. Rails deployment is getting easier and easier, thankfully.
August 27th, 2006 at 07:44 PM I probably wouldn't use some sketchy undocumented server from Russia with no reputation to speak of out in front of any cash-cow apps, but still, as far as mental masturbation goes, nginx is probably worth playing with. I just heard, for what it's worth, that the release of the mongrel-friendly Lighty is about 3-7 weeks (from 28 August) away. Yay for Jan Knescke! I can't wait until there is a solution that lets me get back to Lighty (and away from god-awful-ugly Apache configs.)
August 28th, 2006 at 05:42 PM If you haven't already figured it out, I am a lightyholic. Rumors of other HTTP servers are mere myths. As far as nginx, I'm not too inclined to learn another program's configuration schemes and idiosyncrasies, but to each his own. Ah well... I look forward to everyone re-embracing lighttpd when 1.5.0 is released. :)
August 30th, 2006 at 07:10 AM The last year on Lighty has pretty much convinced me to find something else. If I hadn't come upon Nginx I would have probably been forced back to Apache. Jan's a busy guy and I appreciate his work but he seems to have priorities a bit backward: features get added before critical bugs get fixed (reverse proxy leaks megs of memory an hour under load, nested conditionals *still* don't work consistently) meanwhile we get improved Mongrel support, mod_download_status is back... I've already started the migration to Nginx (about a dozen sites converted already) and it's a breath of fresh air. Configuration is so sane you can pretty much figure it out from looking at the Russian docs, it's *fast*, has the right mix of features and most importantly, the features it has appear to work properly. I'll probably be done migrating the rest of our servers in a week or so and I don't expect we'll go back to Lighty any time soon. Er, not "soon", I meant "ever".
August 30th, 2006 at 07:42 PM @Cliff: I'd love to hear how long ago you started this migration. Any facts, figures, or general info you might have on how nginx works in a production environment would be very helpful to the community at large. Also, Jan is doing a great job with Lighty. How could he have predicted Mongrel's release and fixed all the bugs in the reverse proxy server, which was, prior to Mongrel, not a critical feature as far as most people were concerned? Rails deployment is changing at a pace no developer could keep up with. I don't think Jan is to blame for not being able to predict our needs.
September 17th, 2006 at 08:32 PM @kit My complaint isn't about Lighty supporting Rails, it's about not supporting everything else (i.e. not leaking memory like mad as a reverse proxy, not having broken configuration parser, etc). This has *nothing* to do with Mongrel. The reverse proxy leaking megabytes of memory every hour may not have been critical outside the Rails world, but there's more to the world than Rails you know ;-) My point is simply that adding new features while critical bugs sit in Trac for months isn't a recipe for success (well, unless you're Microsoft... but that's probably why they don't use Trac <wink>). Also, before anyone says anything about helping out: I actually did try to get in and fix some of the bugs that were causing me issues and the state of the source code wasn't reassuring either. I'm not exactly new to C programming (although I don't do it much anymore) and I couldn't wade through the mess in there. Anyway, that aside, if anyone is still interested in Nginx, we've got a new wiki going over at: http://wiki.codemongers.com/Nginx Most (perhaps 70%) of the Russian docs have been translated (although I can't swear to the accuracy of some of them ;-) There's also some deployment tips, example configurations for Mongrel, etc. Sorry to make this more of a negative statement about Lighty rather than a positive one about Nginx, but I can't deny I'm pretty unhappy with the whole affair. Over the last several months I've gone from being a Lighty evangelist to my current state of recommending people avoid it like the plague.
September 20th, 2006 at 05:56 AM I am beginning to agree with Cliff... we should be seeing mod_proxy improvements and fixes first. I am becoming very itchy for a 1.5.0 release, and unless it is delivered soon, I will have to see about using A2 or nginx. I haven't seen the memory problems that Cliff experiences and I don't use nested conditionals, but the "fair" proxy mode does not work well enough for large deployments.
November 23rd, 2006 at 11:03 AM This looks like a worthy front-end for mongrel clusters. I had a quick play and it worked perfectly for my rails apps, however I also require proxying to apache for a number of domains. Currently I have a 'catch all' virtual host with Pound (UrlGroup ".*") - is it possible to do the same with nginx?
November 28th, 2006 at 06:49 AM Hi, I also use mongrel+nginx in the same way you do. I have a problem now that cracks my mind - HTC files. Mongrel shows the menu on mouse over on INTERNET EXPLORER @ http://maoz.octava.co.il:3000/x/test.html While when going through Nginx to the Mongrel @ http://maoz.octava.co.il/x/test.html it doesn't both mongrel & ngnix are configured to support ".htc"s nginx even comes HTC ready from the beginning. any idea?
February 1st, 2007 at 12:26 AM Re: the "cashcow" comment above -- I've made $2k+ in the past month from a RoR app being served up by NGinx / mongrel cluster. It's safe, even with cash cows -- IF you know what you're doing =)
February 5th, 2007 at 02:24 PM Dor Kalev: I cannot open your page now, but the guess is that HTC files are prevented from showing by the same configuration directive that hides .htaccess .htpassword etc. Inspect your config file closely.
March 12th, 2007 at 10:02 AM to get nginx running at boot on gentoo, do: rc-update -a nginx default
May 3rd, 2007 at 08:25 PM It's been 8 months since this post was made, and in the comments they said it would be 3-7 weeks for a new LightTPD; and 1.5 still isn't here yet. If you're holding off to try Nginx, trust me, don't. Its stable, and developing at a pace that is much quicker than LightTPD. I predict that within a year or so, LightTPD won't even be on the map when talking about Rails deployment; or it will be placed intothe same category that Apache and FCGI are in now.
May 4th, 2007 at 03:13 PM I've now been using nginx in production since October (as announced in "nginx + ssl + rails":http://notrocketsurgery.com/articles/2006/11/02/ngnix-ssl-rails) and am very happy with its stability and features. But, that does not mean that lighttpd has dropped off my horizon. For one, lighttpd-1.5.0's mod_proxy_core has more advanced load balancing techniques than nginx's simple round-robin technique (you'll have to dig through the lighttpd blog to find the details). I also find lighttpd's automatic spawn-fcgi ability convenient for using PHP (e.g., for phpMyAdmin). As far as Rails, if Igor were to implement a more advanced mod_proxy module I think you would be completely right.
February 4th, 2008 at 11:16 AM Just one small bit: The link to the runlevels documentation is dead. Not sure if they're still hosting it elsewhere on their site.
February 27th, 2008 at 04:19 AM The link to your smaple nginx.conf file is also dead. Thanks for the useful article, though!