Castle and Riders

Using Capistrano with DreamHost

In my last post, I took a critical look at some of the problems and limitations I discovered while setting up Capistrano 2.0 for deploying my Rails app. Now that my frustrations are fully vented, I can share the details of my setup on DreamHost.

With a quick search I found many, many, many examples of Capistrano configurations for DreamHost. Wow, this sure seems to be a popular host for Rails apps! However, most of the configurations are identical, and none of them worked for me. It almost looks like everyone was copying and pasting from the same (bad) source. I seriously wonder if any of them have been tested in production.

So I decided to create a Capistrano setup that actually works with DreamHost.

Capistrano relies on a file in the config directory called “deploy.rb,” which contains configuration settings and tasks for deploying an app to a remote server. You need to know two things when creating your first deploy.rb:

  1. Capistrano assumes a lot of things are already set up.
  2. The default deploy.rb file is worthless. You have to create your own.

Here are some of the assumptions my deploy.rb makes about my environment:

  • I’ve set up an SSH connection between my local machine and the server.
  • I’m using a subversion repository for my app.
  • My subversion repository is accessible from the server (I can check out the repository when logged into my host).
  • My host username is the same as my svn username.
  • My app is running in development mode locally but needs to be switched to production mode when deployed.
  • My app is using cgi in development but fastcgi in production.
  • My app directory name on the server is the same as my domain name.
  • I have set up an empty spin file in my script file (explained below).
  • I’m using DreamHost as my host.

Enough talk! Let’s take at look at the deploy.rb:

set :user, "my_user_name"
set :application, "gridworlds.com"
set :repository, "http://svn.gridworlds.com/trunk"

The first three lines set up some basics: my username for the server and repository, my application name (which is both the domain of my app and the name of the directory for my app on the server), and the subversion repository URL. Note that the repository must be accessible from the server, which means I need to be able to check out my app when I’m logged in.

role :web, application
role :app, application
role :db,  application, :primary => true

Here I’m creating three standard roles for my application. Since I’m only deploying to a single server, there’s nothing unusual going on.

set :deploy_to, "/home/#{user}/#{application}"
set :use_sudo, false
set :checkout, "export"
set :scm_verbose, true

The :deploy_to setting here is the standard app directory for DreamHost. Since DreamHost does not allow sudo in a shared server environment, I need to set :use_sudo to false. I am also setting :checkout to “export” to avoid checking out .svn directories. Finally, the secret, undocumented :scm_verbose setting! This makes sure “cap deploy” shows all files pulled from the repository by removing the “-q” flag from the svn checkout. This is very handy for troubleshooting if you run into problems with subversion while testing your deploy.rb tasks.

desc "Fix permissions and set environment after code update."
task :after_update_code, :roles => [:app, :db, :web] do
  # set permissions
  run "chmod +x #{release_path}/script/process/reaper"
  run "chmod +x #{release_path}/script/process/spawner"
  run "chmod 755 #{release_path}/script/spin"
  run "chmod 755 #{release_path}/public/dispatch.*"
  # switch to production mode in config/environment.rb
  run "sed 's/# ENV\[/ENV\[/g' #{release_path}/config/environment.rb > #{release_path}/config/environment.temp"
  run "mv #{release_path}/config/environment.temp #{release_path}/config/environment.rb"
  # switch to fastcgi dispatcher in public/.htaccess
  run "sed 's/RewriteRule ^(.*)$ dispatch.cgi/RewriteRule ^(.*)$ dispatch.fcgi/g' #{release_path}/public/.htaccess > #{release_path}/public/.htaccess-temp"
  run "mv #{release_path}/public/.htaccess-temp #{release_path}/public/.htaccess"
end

Here’s my first task, which runs automatically after a subversion checkout. Let’s break it down:

First, I set permissions for all of the executable files, including a spin file. This file was not created by Rails automatically, but “cap deploy” still expects to find it. Without it, you will get an error during deployment. I simply created a blank file named “spin” in my script directory and the error disappeared.

Next, I switch config/environment.rb to production mode by uncommenting the ENV line. I’m using the Unix “sed” command, passing in a regular expression and outputting the results to a temp file, which I rename with “mv” to overwrite the old file.

Finally, I switch public/.htaccess to use fastcgi. This is also a regular expression passed into sed and output to a temp file, which I again rename to overwrite the old file.

desc "Start/restart server after deployment."
task :restart_web_server, :roles => :web do
  run "touch #{deploy_to}/current/public/dispatch.fcgi"
end

I need one more task to restart the Web server. Since I’m running on DreamHost, the recommended way to cycle the server is to modify dispatch.fcgi (which will force it to reload). I can accomplish this easily with the Unix “touch” command, which simply updates the last modified date without actually changing the contents of the file.

after "deploy:start", :restart_web_server
after "deploy:restart", :restart_web_server

And now I set up two post-processing tasks to call :restart_web_server immediately after running the start or restart tasks. Since one of these two is called at the end of every deployment or rollback, my server will always restart automatically.

Now comes the magic of Capistrano. All I have to do is “cd” to the local directory of my app, check in the latest code, and run two commands to start up my app for the first time:

cd ~/Rails/grid
svn commit
cap setup
cap deploy:cold

And for each subsequent update, I simply commit my changes and issue one cap command to deploy the new version:

svn commit
cap deploy

Okay, maybe Capistrano isn’t so bad after all.

Posted on October 5th, 2007 in the Rails category | Permalink
You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a Reply

You must be logged in to post a comment.