At the Forge - Phusion Passenger

by Reuven M. Lerner

I've been using Ruby on Rails for several years now, and I continue to marvel at the ease with which I can create sophisticated Web applications. It's not perfect, but the fact is that Rails has made the hardest parts of Web development fairly painless. ActiveRecord, which lets me work with my database almost effortlessly, is obviously a great achievement, but the other elements of Rails—from database migrations to the templating system to the overall MVC structure—often surprise me with the elegant solutions they offer to common problems. The coming merger with Merb, a lean-and-mean alternative to Rails, leads me to believe that Rails will continue to provide developers with a terrific environment in which to practice their craft.

So, it's been frustrating to me, and to many other developers as well, that although Rails makes it easy to write applications, it makes the deployment of those same applications difficult. Sure, the famous screencasts in which you can create a blog make it clear that you can be up and running in almost no time. But, that's using WEBrick, a simple HTTP server written in Ruby, which no one realistically would use on a production site.

Apache, the HTTP server I have used since it was first released, and which continues to power the majority of Web sites in the world, would appear to be a natural choice for Rails deployment. After all, Rails is an open-source project, and just about every open-source Web framework hooks into Apache, right? Unfortunately not. The interface between Apache and Rails used a protocol known as FastCGI, or FCGI, and the combination of Rails, FCGI and Apache was long considered inferior to other options.

There always have been alternatives. Some sites used lighttpd, which had support for FCGI that was considered superior to what Apache offered. Others switched to Mongrel, which was designed in part to provide a stable and fast option for Rails applications. Some sites combined Mongrel with yet another open-source server, nginx (pronounced “engine-x”), which excels at handling static files. The book Deploying Rails Applications, which I recommend to anyone working on production Rails sites, steps through the configuration of Mongrel and nginx at great length.

For several years, then, deploying a Rails application meant learning to work with a new set of servers. This had several negative impacts. First, it raised the bar for using Rails just a bit more; now programmers needed to learn not only a new framework, but also a new HTTP server too. Another outgrowth was the relative dearth of hosting facilities that could work with Rails. PHP is nearly ubiquitous in the hosting world, in part because it integrates easily with the other elements of the LAMP stack (Linux, Apache and MySQL). Because Rails didn't easily integrate with Apache, it meant that hosting providers would need to learn a new skill and maintain a new package, which they weren't interested in doing.

And so, it was with a great deal of fanfare that Phusion, a Dutch consulting firm that has been using Ruby for the last few years, announced in 2008 that it had released Passenger, otherwise known as mod_rails, a module for Apache that makes it trivially easy to get up and running with a Rails application. I have switched to Passenger for my Rails production sites and have no complaints or regrets about doing so. And, it seems that I'm not alone; the company that originally sponsored the development of Ruby on Rails, 37signals, has indicated that it uses Passenger for some of its applications, and that it is thinking of moving additional applications to it in the future.

Yet another advantage to the fact that we can now use Apache to deploy Rails applications is the availability of other Apache modules. Apache was designed to be highly modular, letting developers include the modules they need, while excluding those that would make the server less efficient. Over the years, this has led to the development of dozens of different modules for Apache, covering everything from authentication to logging, from content negotiation to server administration. Having access to this large pool of useful modules means that our Rails application can be customized in a large number of different ways, providing us with many choices when it comes to deployment.

This month, we look at how to use Passenger to deploy a Rails application. We also look at how we can combine other Apache modules with Passenger for a customized application solution.

Installation

Installing Passenger is a remarkably easy process, assuming that you already have Apache installed on your computer. First, you need to install the Passenger software, which comes as a Ruby gem:

sudo gem install passenger

This installs the Ruby gem (which on my Ubuntu server, is placed in /usr/lib/ruby/gems/1.8/gems), as well as several programs in /usr/bin, which we will use for Passenger. We use the first of these to install the Passenger module for Apache:

passenger-install-apache2-module

This starts the process of installing the Apache module on your computer; Passenger's installer script is smart enough to find many different versions of Apache, in many different places. It looks through Apache, determines what needs to be installed and then prompts you to install required packages automatically. For example, this is the output from the Passenger install program:

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/apache2
 * Apache 2 development headers... not found
 * Apache Portable Runtime (APR) development headers... found
 * Apache Portable Runtime Utility (APR) development headers... found
 * fastthread... found
 * rack... found

If you are missing one or more of these programs, the installer tells you what commands you need to run in order to install the necessary programs. For example, my Ubuntu server indicated that I needed to install Apache 2 development headers and suggested I do this by executing the following:

apt-get install apache2-prefork-dev

I followed those instructions, and it worked. Once I finished installing the additional package via apt-get, I re-ran passenger-install-apache2-module. This time around, it succeeded, compiling the Apache module and adding an appropriate LoadModule directive in the Apache configuration file.

Indeed, now that Passenger is on our system, we can configure one or more Web sites. A simple configuration—indeed, the shortest one—would look like this:


<VirtualHost *:80>
    ServerName www.mysite.com
    DocumentRoot /home/reuven/public
</VirtualHost>

Note that the DocumentRoot points to the public directory of the Rails application, rather than to the Rails root. The Rails application itself is assumed to reside in the app directory parallel to public. Assuming that your Rails application is in place, restarting the Apache server will load the Passenger module, then run your application. By default, Passenger assumes you want to run your application using the “production” environment, which is optimized for system efficiency, rather than programmer interactivity. You can use the RailsEnv configuration directive to set the environment to something else, however:

RailsEnv development

Once your server is running, Apache continues to produce its standard log files (that is, error, access and referrer). Rails also will produce its standard log files in the application's log directory, so if you are used to looking through logs/production.log, you need not fear that it will be going away.

To restart the Rails application, you need to create a file called restart.txt in the application's tmp directory. Once this file is created, Passenger restarts the application, making sure not to interrupt any HTTP requests that it is currently servicing. (In this way alone, it is clearly superior to restarting Apache completely.)

Capistrano

If you use Capistrano to deploy your programs to one or more production servers, you might be wondering how it works with Passenger. The answer is that Capistrano works just fine, but you do need to consider the layout of a Capistrano-enabled server to ensure that everything works correctly.

As you might know, Capistrano keeps several versions of a Web application around. Each version is stored in its own directory, within the releases directory. A symbolic link, called current, points to the subdirectory inside of releases that corresponds to the current version. This means that reverting to a previous version is nearly instantaneous, because it involves redefining the symlink to point to a previous subdirectory of releases.

So, on a Capistrano-enabled system, you will want your Apache configuration to look like the following:

DocumentRoot /home/reuven/current/public/

Notice the introduction of /current into the DocumentRoot. This tells Apache that it should use the current symbolic link and, thus, treat whatever current points to as the live version of the application.

But, what happens when you want to deploy a new version of your application? Capistrano is smart enough to rewrite the symbolic link, but it doesn't natively know how to restart the server. Fortunately, as we saw before, a restart involves creating the restart.txt file, so a Passenger-friendly recipe (inside of deploy.rb) could look like this:

namespace :deploy do
  desc "Restart Application"
  task :restart, :roles => :app do
    run "touch #{current_path}/tmp/restart.txt"
  end
end

Now, when we issue the cap deploy command, it knows to restart the server by creating restart.txt in the application's tmp directory. If we are interested only in restarting the server, we can do so by issuing the cap deploy:restart command, which runs just the restart task inside the deploy namespace.

Monitoring

Passenger comes with a number of utility programs that make it easy to keep track of your server's status and resource use. The program passenger-memory-status, for example, lists all the current processes being used by Apache, as well as the number of threads that each process has spawned. It then describes the amount of memory that each of those processes is using. For example, here is the memory usage report for ten Apache processes on a production Web server:

root@kipling:~# passenger-memory-stats
-------------- Apache processes ---------------
PID    PPID   Threads  VMSize    Private  Name
-----------------------------------------------
2941   15559  1        11.9 MB   0.5 MB   /usr/sbin/apache2 -k start
2944   15559  2        132.5 MB  9.1 MB   /usr/sbin/apache2 -k start
7392   20753  27       234.0 MB  6.8 MB   /usr/sbin/apache2 -k start
13383  20753  2        124.0 MB  7.9 MB   /usr/sbin/apache2 -k start
15559  1      1        11.9 MB   0.5 MB   /usr/sbin/apache2 -k start
15563  15559  2        147.7 MB  8.7 MB   /usr/sbin/apache2 -k start
17357  20753  1        11.9 MB   0.5 MB   /usr/sbin/apache2 -k start
17362  20753  27       239.8 MB  12.8 MB  /usr/sbin/apache2 -k start
17477  20753  27       236.6 MB  7.8 MB   /usr/sbin/apache2 -k start
20753  1      1        11.9 MB   0.4 MB   /usr/sbin/apache2 -k start
### Processes: 10
### Total private dirty RSS: 54.95 MB

That same command also shows us the current memory status for our Passenger (that is, Ruby) processes. It shouldn't come as any surprise to learn that the Ruby processes typically will be much larger than the Apache ones. Indeed, monitoring the memory usage of the Rails processes is an important thing for Rails developers to do; without such feedback, it will be difficult to measure how efficiently processes are working.

Other Apache Modules

Finally, as I mentioned previously, one of the best parts of using Apache for Rails applications is the fact that you can mix and match other Apache modules, as you like. For example, I am a big fan of both mod_status and mod_info, two modules for Apache that make it possible to peek into the server's current configuration and execution state.

In the same way, I wanted to compress files automatically as they were sent from my server to the user's browser. By incorporating mod_deflate into my server configuration, I was able to add automatic, on-the-fly compression with the following directive:

SetOutputFilter DEFLATE

Finally, I recently worked on a simple Rails site that wanted to restrict access to items under the /admin URL to authorized users. I could have used a Rails plugin, such as restful_authentication, but as I was using Passenger, I thought it might be just as easy and fast for me to use HTTP authentication on the site, defined in the Apache configuration file. Sure enough, the following was enough to do the trick:


<Location /admin>
  AuthName "Site admin"
  AuthType Basic
  AuthUserFile /opt/mysite/users

  require valid-user
</Location>

Of course, you could argue that this sort of authentication is far less flexible than a Rails-based one, and you would be right. But for a site that has very simple needs, and that doesn't need something as fancy as restful_authentication, Apache's built-in (and well documented) HTTP authentication is a good solution.

Conclusion

The beauty of Apache is its flexibility, and Passenger makes it possible for us to incorporate that flexibility into our Rails applications, using the same server software that we've used for years.

Phusion Passenger has made it easier to deploy Rails applications, which is a good thing for Rails developers everywhere. It not only allows you to use your existing knowledge of the Apache server, but also means you can incorporate some of the many modules that have been developed for Apache over the years.

Resources

You can learn more about Ruby on Rails at www.rubyonrails.com. Information about Phusion Passenger is at www.modrails.com. The site contains a great deal of documentation, including a full list of configuration directives that allows you to customize fully the way that Passenger is deployed for your site.

The book Deploying Rails Applications, published by the Pragmatic Programmers and written by several well-known Rails developers, doesn't include a description of Passenger. But, it does have a large number of other, good suggestions for rolling out Rails applications, and all Rails developers would do well to look at this book, including the many useful hints that it offers.

Reuven M. Lerner, a longtime Web/database developer and consultant, is a PhD candidate in learning sciences at Northwestern University, studying on-line learning communities. He recently returned (with his wife and three children) to their home in Modi'in, Israel, after four years in the Chicago area.

Load Disqus comments