Whew. That’s a long title. I am talking about taking an existing Rails application deployed with Apache and Mongrel and upgrading it to use Phusion Passenger and Ruby Enterprise Edition.
Here’s what I did.
Install Ruby Enterprise Edition
First, if you’re going to use Phusion Ruby Enterprise Edition (I wanted to because of the recent Ruby security problems) I recommend starting with that first. Installation is straight-forward and does not conflict with your existing Ruby installation.
It supposedly can pick up gems installed with your old copy of Ruby, but I couldn’t figure out how to get that to work, so I had to install some gems again. You do that like this:
sudo /opt/ruby-enterprise-1.8.6-20080709/bin/gem install gem-name
We vendor all our gems except for a few that require native compilation or I just plain can’t get working in the vendor directory. I had to install hpricot, mime-types, and image_science.
The reason to start with Ruby Enterprise Edition is that you’ll have to reconfigure Passenger to use it if it’s not installed already.
Install Passenger
Next, install Passenger. Again, this is straight-forward. However, make sure you install it with the Ruby Enterprise Edition binary.
sudo /opt/ruby-enterprise-1.8.6-20080709/bin/gem install passenger
Then build the Apache module. You may need to install the Apache development header files if they’re not already there.
sudo /opt/ruby-enterprise-1.8.6-20080709/bin/passenger-install-apache2-module
This will give you some lines of code to put in your httpd.conf file. Since you used Ruby Enterprise Edition to run the command, the PassengerRuby variable, the PassengerRoot, and the location of the mod_passenger.so will be inside your /opt/ruby-enterprise-X.X.X-YYYYMMDD directory tree.
Update Rails configuration
Now you need to remove mod_proxy_balancer and mod_rewrite from your application’s Apache config file. The DocumentRoot you had before ought to be fine—Passenger can detect when Apache is serving up a Rails application.
This is what I had in my config file before:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# Configure mongrel_cluster <Proxy balancer://tumblon_cluster> BalancerMember http://127.0.0.1:8000 BalancerMember http://127.0.0.1:8001 </Proxy> RewriteEngine On # Prevent access to .svn directories RewriteRule ^(.*/)?\.svn/ - [F,L] ErrorDocument 403 "Access Forbidden" # Check for asset hosts RewriteRule %{REMOTE_HOST} ^assets\d.* [L] # Check for maintenance file and redirect all requests RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f RewriteCond %{SCRIPT_FILENAME} !maintenance.html RewriteRule ^.*$ /system/maintenance.html [L] # Rewrite index to check for static RewriteRule ^/$ /index.html [QSA] # Rewrite to check for Rails cached page RewriteRule ^([^.]+)$ $1.html [QSA] # Redirect all non-static requests to cluster RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f RewriteRule ^/(.*)$ balancer://tumblon_cluster%{REQUEST_URI} [P,QSA,L] |
Obviously, we are not using mod_proxy_balancer at all, so that can just go (also watch out for the last RewriteRule, wich uses the balancer).
The RewriteRules – for the most part – aren’t needed because Passenger handles cached pages automatically. Also, Passenger conflicts with mod_rewrite and turns it off by default, so they don’t work anyway.
I don’t have an alternative for the maintenance page, but I don’t use that anyway.
Bonus tip: Set your Rails environment. If you application runs in anything other than production, you need to set it here. I have a staging server that runs in its own environment, so I set it like so:
RailsEnv staging
Update Capistrano configuration
Only one more thing: update your deployment recipe. You don’t need to restart mongrel_cluster because there won’t be one.
I’m still in the dark ages using Capistrano 1.4.1, so this is the task I came up with:
1 2 3 4 5 6 7 8 9 10 |
desc "Restart Phusion Passenger (restarts Apache)" task :restart_app, :roles => :app do sudo "#{apache_ctl} restart" end desc "Override the built-in restart task to restart Apache" task :restart, :roles => :app do restart_app end |
Overriding restart is important because that’s what Capistrano will run. The default deprec version I was using restarted mongrel_cluster. This one restarts Apache.
You can restart Passenger by touching RAILS_ROOT/tmp/restart.txt but I prefer just to restart Apache.
And that’s about all there is to it.


I’ve been toying with moving from Nginx/Mongrel to Apache/Passenger ( http://blog.matt-darby.com/2008/07/24/maybe-i-spoke-too-soon/) and I totally missed compiling/installing Passenger with REE! I installed Passenger first, then REE.
That’s why I put it in there. That’s exactly what I did, but I think it’s easier if you install REE first.
Thanks for the great post Luke. Have you had it running enough to be able to tell what performance gains the Enterprise Ruby Edition from Phusion gives? I’d love to see some benchmarks and comparisons to standard Ruby.
- Robert
Just so you know, rather than restarting Apache in its entirety when you deploy, you can just restart Passenger (mod_rails) instead. What I put below will work for you – take out the “namespace” scope for Capistrano versions below 2.0.
namespace :deploy do desc “Restart Application” task :restart, :roles => :app do run “touch #{current_path}/tmp/restart.txt” end end
Hey Robert, thanks for stopping by.
I’ve just done this recently on our staging server, so I haven’t done any benchmarks or anything. The two main reasons I did this are so I don’t have to install monitoring for the mongrels and so I could get the Ruby security patch without screwing up my app (still no known good official patch for Rails 2.0? WTF?).
Actually it’s not necessary to install Phusion Passenger after REE. You can do it in any order. The REE installer will tell you to change the ‘RailsRuby’ option in Apache if you’re using Phusion Passenger (or, equivalently, the ‘PassengerRuby’ option, which is an alias for ‘RailsRuby’), and that’s all you have to do to tell Phusion Passenger to use REE instead of normal Ruby. Phusion Passenger will be correctly located by REE even if it wasn’t installed via REE.
Hongli, right, that is true, and in fact I did install Passenger before REE.
I’m just saying it’s easier to do REE before Passenger because they you don’t have to change the config file.