Your friends at Viget present Extend, a Code & Technology Blog

Passenger: Let It Ride?

Rails application deployment has gotten a pretty bad rep. Legitimate Rails developers and blog trolls alike have bemoaned the lack of something equivalent to mod_php, which would make Rails applications "just work" when uploaded to a web server, as we got used to doing in the PHP days.

So Passenger made a big splash when it was released this month. It promises to make deployment "a breeze" and says "No Ruby on Rails-specific server configuration [will be] required!" Furthermore, the developers' own benchmarks show it being a little faster than Mongrel.

After a decade-plus in IT, I'm skeptical of hype and twice as skeptical of benchmarks. But even though I've mastered the sometimes-confusing realm of Apache and Mongrel, I'm curious to see just how easy it is to use, and just how fast.

I'll save the benchmarks for a future article and concentrate on ease of setup and use. I logged in to a Slicehost VPS running CentOS 5.1 (on x86_64 hardware) and opened the user's guide. The first step is to get the software installed. I chose the gem install:

$ sudo gem install passenger
Building native extensions.  This could take a while...
Successfully installed rspec-1.1.3
Successfully installed activesupport-2.0.2
Successfully installed activerecord-2.0.2
Successfully installed actionpack-2.0.2
Successfully installed actionmailer-2.0.2
Successfully installed activeresource-2.0.2
Successfully installed rails-2.0.2
Successfully installed passenger-1.0.1
8 gems installed

So passenger depends on the Rails gems, as well as RSpec. Nothing you wouldn't find in an average Rails application.

Next step is to install Passenger's Apache module. This one-line command attempts to check for needed dependencies before building the code:

$ sudo passenger-install-apache2-module 
Welcome to the Passenger Apache 2 module installer.

This installer will guide you through the entire installation process. It
shouldn't take more than 3 minutes in total.

Here's what you can expect from the installation process:

 1. The Apache 2 module will be installed for you.
 2. You'll learn how to configure Apache.
 3. You'll learn how to deploy a Ruby on Rails application.

Don't worry if anything goes wrong. This installer will advise you on how to
solve any problems.

Press Enter to continue, or Ctrl-C to abort.

Checking for required software...

 * GNU C++ compiler... found at /usr/bin/g++
 * Ruby development headers... found
 * OpenSSL support for Ruby... found
 * RubyGems... found
 * Rake... found at /usr/bin/rake
 * Apache 2... found at /usr/sbin/httpd
 * Apache 2 development headers... found at /usr/sbin/apxs
 * Apache Portable Runtime (APR) development headers... found
 * fastthread... found
--------------------------------------------
[...]

Unfortunately, it missed one dependency which I didn't have installed: the headers for libuuid, which are provided in RHEL/CentOS by the e2fsprogs-devel RPM. So let's install that and try again:

$ sudo yum -y install e2fsprogs-devel
[...]
Installed: e2fsprogs-devel.i386 0:1.39-10.el5_1.1 e2fsprogs-devel.x86_64 0:1.39-10.el5_1.1
Complete!
$ sudo passenger-install-apache2-module 
[...]
The Apache 2 module was successfully installed.

Please edit your Apache configuration file, and add these lines:

   LoadModule passenger_module /usr/lib64/ruby/gems/1.8/gems/passenger-1.0.1/ext/apache2/mod_passenger.so
   RailsSpawnServer /usr/lib64/ruby/gems/1.8/gems/passenger-1.0.1/bin/passenger-spawn-server
   RailsRuby /usr/bin/ruby

After you restart Apache, you are ready to deploy any number of Ruby on Rails
applications on Apache, without any further Ruby on Rails-specific
configuration!

OK, much better. After adding those three lines to /etc/httpd/conf.d/passenger.conf and restarting, we are ready to configure an application in Apache. According to the final output of the passenger-install-apache2-module program, this is all we need:

<VirtualHost *:80>
ServerName www.yourhost.com
DocumentRoot /somewhere/public
</VirtualHost>

Seriously? OK, let's go into the Apache configuration and comment out all of our mod_proxy and mod_rewrite configuration for our application, leaving just the lines mentioned above, and restart Apache...

Splat! Not quite there yet. We get our 500 error page. A quick look at the log reveals:

ActionView::TemplateError (undefined method `markdown' for #<ActionView::Base:0x
2aaaaba0ed50>) on line #1 of stories/index.html.erb:
1: <%= render :partial => 'story', :collection => @stories %>

That's interesting, because bluecloth.rb is in our vendor/ directory. But let's try again after installing the BlueCloth gem. Nope, still getting the 500 error. We need to tell the application to restart. We do this by creating a file called "restart.txt" in our app's tmp/ directory:

$ sudo gem install BlueCloth
Successfully installed BlueCloth-1.0.0
1 gem installed
$ cd current/tmp/
$ touch restart.txt

Well, that apparently wasn't enough. Only after restarting the entire Apache process did the 500 error go away. Not too reassuring. Let's try modifying the code, then touching that restart.txt file again to see if the change gets picked up.

$ vim app/controllers/stories_controller.rb
[... change some code ..]
$ touch tmp/restart.txt

This time it worked. Maybe certain things need a "hard" restart? I'm not sure why code located right in vendor/ didn't get loaded, but my gems in vendor/gems/ did. In any case, arranging for Capistrano to create this tmp/restart.txt file is pretty simple; just add this to your Capfile:

namespace :deploy do
  desc 'Signal Passenger to restart the application.'
  task :restart, :roles => :app, :except => { :no_release => true } do
    run "touch #{release_path}/tmp/restart.txt"
  end
end

So there you go. Aside from the hiccup with loading bluecloth.rb, it really does work as advertised. In a future article we'll see if those benchmarks really stand up.


Get More From Viget

Subscribe to get our monthly newsletter and occasional special announcements.