I’ve been down with the flu and confined to the couch for the last couple of days, so what better way to pass the time than learning a new web framework and deploying it to Dreamhost? Only a brain cooked by fever would think something like this might qualify as fun, but my grey matter is pretty close to hard-boiled by now, and I can only play so much WoW before wanting to shoot myself. So I fired up Google and a text editor and started hacking away.
Enter Sinatra
The most pleasant part of this whole experience was picking up Sinatra, a minimal Ruby web framework that hearkens back to the simpler days of shoving a bunch of Perl into a CGI script and calling it a day. Like the CGI script of yore, you can easily stuff a small app into a single file. Unlike that CGI script, Sinatra lends itself well to MVC separation, test- or spec-driven development, and other modern programming conveniences. It’s ideal for slapping a quick user interface on some Ruby code.
Sinatra’s readme is a great drink-from-the-fire-hose introduction to what the framework can do, but the minimal “hello world” application on Sinatra’s home page is a bit too minimal to be instructive. There are some great tutorials listed on the Sinatra site, though. In particular, I found Building an iPhone web app in under 50 lines with Sinatra and iUI to be just the ticket for quickly getting up to speed on what Sinatra does. As an added bonus, it’s got iPhone stuff in it, which is worth at least two squares in Buzzword Bingo.
Dreamhost, prepare to be boarded
The first step is to make a domain in the Dreamhost panel and configure it to run Passenger. From what I’ve been reading, Passenger isn’t really set up to run apps in a subdirectory (like example.com/myapp), so a new subdomain is the way to go here (like myapp.example.com). Dreamhost lets you define as many subdomains as you want, so this isn’t a problem; just click Add New Domain / Sub-Domain in the Domains > Manage Domains screen.

On the Fully Hosted page that appears, check the Ruby on Rails Passenger box. Then set up the web directory as you would for any other site, but add current/public to the end of the path. We’re using Capistrano to deploy the app, and Capistrano wants to deploy to a directory called current. Passenger expects the web directory to point to the app’s public folder. Combining those two makes a path ending in current/public.

Let Dreamhost do its thing and create the new domain. Depending on how flaky its systems are and the current phase of the moon, you may have a working subdomain in a few minutes or several hours. I failed my saving throw versus Broken Scripts and got the several hours version when I set up the domain yesterday, resulting in the dreaded bad_httpd_conf error. You can sometimes force Dreamhost to rebuild your messed up httpd configuration by going back to the Fully Hosted page and just clicking the Fully host this domain now button. No need to change any settings on the page; apparently, performing this little ritual will kick the scripts into gear, and with luck, you’ll have a working subdomain with Passenger running on it.
When Dreamhost’s scripts get around to creating the domain, they’ll also create its web directory. You’ll need to ssh over to your account and delete the current directory that’s there. Capistrano recreates current as a symbolic link pointing to the currently deployed version of the application.
> cd ~/sites/sinatra-test.nyerm.com > rm -rf current
Vendoring Sinatra and Rack
Though it’s possible to get your own local gem repository working on Dreamhost (and for some gems, like RMagick, necessary), I find it simpler to unpack gems required by the app into a vendor folder and just deploy them with the rest of the application.
As I write this, Dreamhost doesn’t have Sinatra installed at all, and its copy of Rack is version 0.4.0, which is incompatible with the latest Sinatra (0.9.1.1). So, I unpacked both of these gems into a vendor folder. Run these commands from the root of your Sinatra project:
> mkdir vendor > cd vendor > gem unpack rack > gem mv rack* rack > gem unpack sinatra > gem mv sinatra* sinatra
Be sure to change the require 'sinatra' line at the start of your application so it requires the vendor copy of Sinatra:
require 'vendor/sinatra/lib/sinatra'
Capifying and racking
With Dreamhost ready to receive your application, it’s time to get Capistrano in on the action. First you’ll need to create a Capfile so Capistrano knows where your application’s source is and where it should be deployed.
> capify .
Open Capfile in your favorite editor and replace the sparse default contents of the file with something more like this:
load 'deploy' if respond_to?(:namespace)
default_run_options[:pty] = true
# be sure to change these
set :user, 'username'
set :domain, 'domain.com'
set :application, 'myapp'
# the rest should be good
set :repository,
"#{user}@#{domain}:git/#{application}.git"
set :deploy_to,
"/home/#{user}/#{application}.#{domain}"
set :deploy_via, :remote_cache
set :scm, 'git'
set :branch, 'master'
set :git_shallow_clone, 1
set :scm_verbose, true
set :use_sudo, false
server domain, :app, :web
namespace :deploy do
task :restart do
run "touch #{current_path}/tmp/restart.txt"
end
end
I found a number of sites with reasonable instructions for deploying Sinatra to Dreamhost, and my favorite is John Nunemaker’s guide on RailsTips. The Capfile above is from his article, which is well worth a look.
The bits that you might need to change in the Capfile here, aside from the obvious :user, :domain, and :application fill-ins, are the :repository and :deploy_to paths. For example, I keep my personal Git repository in a directory that’s served out by Apache so I can browse the contents. Also, my file structure has an extra sites directory above the web roots, because I don’t like the mess that Dreamhost’s default paths make of my home directory. The appropriate portion of my Capfile looks like this:
set :repository,
"#{user}@#{domain}:sites/git.nyerm.com/#{application}.git"
set :deploy_to,
"/home/#{user}/sites/#{application}.#{domain}"
The last ingredient needed for deployment to Dreamhost is a rackup configuration file, config.ru. Pop open the text editor again and enter the following:
require 'vendor/rack/lib/rack' require 'vendor/sinatra/lib/sinatra' set :run, false set :environment, :production set :views, "views" require 'hi.rb' run Sinatra::Application
Deploying to Dreamhost
Check all your files in and push to the remote Git repository, and you should be ready to deploy with the following commands:
> cap deploy:setup > cap deploy
Assuming you don’t have any typos and Dreamhost is choosing to be merciful, you should now have a Sinatra app running on Dreamhost. On the other hand, if like me you’re not a divine being of pure logic, you might want to enable Rack’s logging middleware so you have some clue what’s not working. Stick the following in your config.ru, and you’ll get something more useful than you’ll find in the Apache logs:
log = File.new("log/sinatra.log", "w")
STDOUT.reopen(log)
STDERR.reopen(log)
Credit where credit is due
I found the following articles helpful when trying to get all this working:
One Comment
Good words.