Jens Krämer

Mongrel, Apache and Rails on Debian Sarge

 |  apache, mongrel, ruby, rails, linux, debian

Wouldn’t it be cool if you just could

apt-get install mongrel

to set up the great Mongrel web server including a recent version of Ruby and everything else needed to run your Rails applications in a combined Mongrel/Apache load balanced setup on a rock solid and easy-to-maintain Debian Sarge server ?

If the answer is yes, this one is for you.

Not that I don’t like gem, but on production systems I prefer to have as less package mangement systems as possible ;-)

So the goal is to set up such a server, without doing a single gem install or ruby setup.rb. We’ll need to install rubygems itself, though, since Mongrel depends on it. But as there’s already a debian package for this, there’s nothing to worry about.

Get it

At first, add the following lines to your /etc/apt/sources.list:

# Ruby 1.8.4, Mongrel, Rake
deb http://debian.jkraemer.net/apt  sarge main contrib non-free
#rubygems
deb http://ftp.de.debian.org/debian/ experimental main contrib

The first repository will give you access to the Ruby 1.8.4 and Mongrel debian packages. The second repo is for RubyGems, which Mongrel depends upon. Thanks to the Debian/Ruby Extras team I didn’t need to package this myself :-). Don’t be afraid of the experimental, we’ll take care that your server stays stable now:

Add this to /etc/apt/preferences to give packages from the experimental repository a low priority:

Package: *
Pin: release a=experimental
Pin-Priority: 100

And finally, tell apt that you want to have a stable system by adding this to /etc/apt/apt.conf:

APT::Default-Release "stable";

If one of the latter two files doesn’t exist, just create it.

Now, type

apt-get update
apt-get install mongrel

This should pull in Ruby 1.8.4 and some other dependencies automatically.

If you’re not running Apache 2.2 (which usually is the case on Sarge systems), you should apt-get install pen, too. This will give you the Pen load balancer we’ll use to distribute traffic between multiple Mongrel instances. With Apache 2.2, mod_proxy can take over Pen’s job, see here for details on this.

Configuration

Mongrel

To give Mongrel a test drive, you should have a Rails application installed somewhere on your server. Each application gets it’s own config file in /etc/mongrel/sites-enabled/. The name of the config file will be used in start, restart and stop commands, so be sure to choose something meaningful.

Here’s an example config, comments included:

# RAILS_ROOT of your application
dir=/home/webapps/your_application/current
# port the first mongrel instance should listen to, additional instances will use ports above this
port=8100
# number of mongrel instances
servers=3
# port pen will listen on
proxy_port=8001

By default, Mongrel will be run under the www-data account, just like Apache, too. This can however be overridden by setting the USER variable in /etc/default/mongrel to some other account on your server. Just make sure the user has write access to the tmp and log directories of your app. Write access to public is needed for Rails page caching. I usually simply set the owner of these directories to www-data:

chown -R www-data tmp log public

If you’re using capistrano for deployment, you have to repeat this for tmp and public after each deployment (log is symlinked from shared and therefore will keep it’s permissions during deployments). A custom after_update_code task might look like this: task :after_update_code do sudo "chown -R www-data #{release_path}/public #{release_path}/tmp" end

Apache

Now we tell Apache to forward requests for your app to the load balancer. You’ll need mod_proxy and mod_rewrite for this. a2enmod {proxy|rewrite} can be used to enable the modules, in case they aren’t yet.

Here’s a snippet to put into the VirtualHost section for your app:

# mod_proxy config
ProxyRequests Off
<Proxy *>
  Order deny,allow
  Allow from all
</Proxy>

# send all requests to URIs not corresponding to real files to the load balancer:
RewriteEngine On
RewriteRule ^/$ /index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}   !-f
# 8001 is the proxy_port from mongrel configuration of your app
RewriteRule .* http://localhost:8001%{REQUEST_URI} [P,QSA]

Run it

You can host any number of applications with this setup, and control them all at once with a simple

/etc/init.d/mongrel {start|stop|reload|restart}

To control a single application, just pass the name of it’s config file as second parameter to the init script:

/etc/init.d/mongrel {start|stop|reload|restart} your_application

The init script will take care of Pen, too. For each application, a Pen process will be launched to distribute requests among the configured port range from port up to port+servers-1

Automatic startup/shutdown

Run

update-rc.d mongrel defaults

and Mongrel will be started/stopped automatically when you start or shutdown your system.

Finished!

If you freeze Rails and any other dependencies right into your applications (which is a good idea anyway, just think of different applications using different versions of libraries), you’re done now.

/etc/init.d/mongrel start your_application

should fire up Pen and the number of mongrel servers you configured.

For now, this setup is running fine on two production servers. If you encounter any problems, please drop me a line.

As my spare time permits, I’ll try to keep up with the fast development of Mongrel, and provide new packages for new versions.

Comments

Ezra Zygmuntowicz

THis is totally sweet man. Thanks for your work on this. Mind if I mention it in my rails deployment book? Will you be keeping these packages up to date?

jk

Thanks and please feel free to do so!

I'll do my best to keep the packages up to date.