Racking up a Serve project on Phusion passenger

Serve is a rapid prototyping framework that I have been building for Web applications. It is specifically designed to make it easy to prototype Rails applications, but it can easily be used to prototype applications for any other framework. I’ve talked about the benefits of using Serve before, so I won’t cover that here, but if you are interested in learning more about Serve read, Serve: A Rapid Prototyping Framework for Designers.

Yesterday I released Serve 0.11.2 which adds built-in support for Rack. Rack allows a Ruby application to be deployed in any number of environments (Mongrel, CGI, Passenger, etc.). The good news for Serve users is that you can now deploy Serve projects much like any other Rails application.

Today, I’d like to talk about setting up your Serve project for deployment on Passenger (a.k.a. mod_rails). Passenger is an Apache/Nginx module that allows you easily deploy Rack-based applications in production environments. The benefit for Serve users is that with Rack and Passenger, Serve is much easier to deploy on a modern Web server. This will allow you to put your prototype project on a Web server that is easily accessible by your clients. Or, if you are on a Mac and you prefer to stay away from the command line, you can use Passenger and the Passenger Preference Pane to handle your Serve projects.

I’m not going to cover the setting up Passenger in this tutorial. That is already well documented on the Passenger web site. Instead I’m going to talk about how to convert your Serve project so that it works well with Passenger.

Passenger requires that Rack applications have a certain structure for performance and security reasons.

The Basics

We learn from the Passenger User Guide that Rack applications must have three things:

The tmp directory is used by Passenger for the restart.txt file. You can notify Passenger that your Rack application should be restarted by updating the Last-Modified timestamp on the restart.txt file. The public directory is needed for static assets like images, javascripts, and stylesheets — in this case anything that is not processed by Serve directly. The config.ru file is a Ruby-based configuration file for Rack.

I’m going to suggest that we add one more directory:

In the views directory we’ll put all of the ERB, HAML, and special Serve files that are necessary for the prototype. Anything that does not need to be processed by Serve should go in the public directory. This includes all images, javascripts, etc. CSS files should also go in the public directory, but SASS or SCSS files should go in the views directory.

To create these directories and files, you can execute the following commands from the command line in the root of your project:

$ mkdir tmp
$ touch tmp/restart.txt
$ mkdir public
$ mkdir views
$ touch config.ru

Now move all of your existing Serve files into the views directory (ERB, HAML, SASS, Redirects, etc…). Be sure to preserve the existing directory structure. If you have a view_helpers.rb file that should also go in the root of views directory.

Once that is complete, move images, javascripts, and other static assets into the public directory. Again, be sure to preserve the existing directory structure. (If a file was in images/icons it should now be in public/images/icons.)

Rack Configuration

Now open up config.ru in your favorite text editor and insert the following code:

gem 'activesupport', '2.3.5' # version required by Serve
gem 'serve'

require 'serve'
require 'serve/rack'

# Middleware
use Rack::ShowStatus # Nice looking 404s and other messages
use Rack::ShowExceptions # Nice looking errors

# The project root directory
root = File.dirname(__FILE__)

# Rack Application
if ENV['SERVER_SOFTWARE'] =~ /passenger/i
  # Passenger only needs the adapter
  run Serve::RackAdapter.new(root + '/views')
else
  # We use Rack::Cascade and Rack::Directory on other platforms to
  # handle static assets
  run Rack::Cascade.new([
    Serve::RackAdapter.new(root + '/views'),
    Rack::Directory.new(root + '/public')
  ])
end

Advanced users may want to modify this a bit to include other middleware or applications, but this configuration should suffice for the basic Serve project. I’ve included the Rack::ShowStatus and Rack::ShowExceptions middleware to provide pretty 404s, messages, and error handling. To turn off either of these features just comment out the appropriate line. Rack::Cascade and Rack::Directory are used to handle files in the public directory if Passenger is not used. This is useful if you are using Rack from the command line via the rackup command.

So that’s it! Everything you need to know to rackup a Serve project on Passenger.

© 2013 John W. Long