Upgrading an existing application to Phusion Passenger and Ruby Enterprise Edition

Posted by Luke Francl
on Friday, July 25

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.

Comments

Leave a response

  1. Matt DarbyJuly 25, 2008 @ 07:05 PM

    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.

  2. Luke FranclJuly 25, 2008 @ 08:33 PM

    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.

  3. Robert DempseyJuly 25, 2008 @ 09:07 PM

    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

  4. Brady BouchardJuly 25, 2008 @ 10:29 PM

    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

  5. Luke FranclJuly 25, 2008 @ 10:29 PM

    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?).

  6. Hongli LaiJuly 26, 2008 @ 03:49 AM

    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.

  7. Luke FranclJuly 26, 2008 @ 09:45 PM

    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.