Using Capistrano

“We will encourage you to develop the three great virtues of a programmer: laziness, impatience, and hubris.”—Larry Wall, Programming Perl

For most programmers, deployment is an area that could do with a touch of laziness. Deploying to a cluster—or even one machine—can be repetitive and tiring. Enter Capistrano, a Ruby deployment tool that makes the task of deploying an application to servers easier by running defined tasks for you on the remote servers.

The Ruby programmers' toolbox contains so many tools for eliminating most of their work, it's fair to say that Ruby programmers are probably some of the laziest. If having all the boring jobs done for you isn't enough, Ruby programmers even contrive to have most of their tools built in one language—Ruby. No bash-make-PHP-Perl combinations. It's all Ruby.

Think of Capistrano as a build system that specializes in running commands remotely on any number of machines. If you have to connect to a half-dozen machines to push updates, or have no quick-and-easy way of rolling back the entire cluster if (or when?) something goes wrong, you need to be a little more lazy.

Capistrano groups tasks in recipes, and the default recipe, which we'll look at in a moment, is very geared toward Rails, running migrations and restarting the Rails server. However, Capistrano's core is not Rails-specific. You can build your own recipes for all your dullest tasks, and you can tweak the Rails recipe to work with whichever language or framework you're using.

Let's take a look at what Capistrano does for Rails deployment, how to build your own tasks and how to push your own application out to 20 servers with just one command.

Capistrano and Rails

Like Rails, Capistrano increasingly is deployed with flavours of Linux and is installed by default in Leopard, so you might not even have to install it. If you do need to, installing Capistrano is as easy as any Ruby gem. Simply run:

sudo gem install -y capistrano

Capistrano has two main commands: cap, which is used for viewing and running the tasks, and capify, which is used to set up a Rails project for use with Capistrano. Assuming you have a Rails project, grab a copy of it, and run capify at the project root:

cd path/to/project capify .

This creates just two files: Capfile and config/deploy.rb. Capfile is to Capistrano as Makefile is to make and Rakefile is to rake. Capistrano expects a Capfile to be present and to contain the tasks or to include a Ruby file that does.

In this case, the Capfile just includes config/deploy.rb, so the latter is the one of interest. The deploy file contains a bunch of settings you need to take care of before running cap, starting with:

set :application, "set your application name here"
set :repository,  "set your repository location here"

If you aren't used to Ruby's syntax, this all will look deceptively like simple configuration. However, because you don't have to use brackets when calling functions in Ruby, each line actually is a call to the set() function in Capistrano's core:

set(:application, "your-app-name")

Set the :application variable to a name without spaces—this will be used to create a deployment directory later. Set :repository to your versioning repository's URL (in this example, we use SVN).

If you have a user name and password for SVN, set them with the lines:

set :scm_username, "svn-username" 
set :scm_password, "svn-password" 

Then, uncomment and set the deployment directory. If the deploy_to doesn't exist on your deployment server, Capistrano creates it:

set :deploy_to, "/path/to/doc/root/www/#{application}"

Here, we're using the application variable we set previously to set part of the deploy_to variable. This is all standard Ruby syntax, available in all Capistrano scripts, making this way of working extremely powerful and a little less cumbersome than a hodge-podge of obscure syntaxes.

Finally, we need to set the servers that will host the deployment. You can add as many servers as you like, and the server name just has to be something that SSH understands—for example:

role :app, "app-server-1", "app-server-2", "app-server-3"
role :web, ""
role :db,  "db-server-1", :primary => true

If you're just testing out Capistrano, it's worth setting the deployment location as your working machine; that way, you can learn without moving between machines:

role :app, "me@my-local-ip"

Now we're ready to ask Capistrano to set up the deployment location using the command:

cap deploy:setup

When you run this, Capistrano starts showing you what it's doing. This helps when debugging Capfiles, and it reassures you that you're doing the right thing. Whenever you connect to another server, you'll be prompted for the password, as usual, after which Capistrano will run a bunch of other commands.

After deploy:setup, the deployment directory now contains some extra directories that will allow cap to push new versions, do rollbacks and so on:

      releases/ shared/log shared/pids shared/system

Next, we get on and deploy the application. Capistrano will check out the source, put it into releases and create a symlink to it called current:

cap deploy:cold

After this has run, take another look in the deployment location:

# current@ -> /www/captest/myapp/releases/20080614144520

This a “cold” deployment, meaning tasks that are one-time tasks are run. To deploy the application in the future, you simply use the deploy task:

cap deploy

When you've run either deploy:cold or deploy, have a look in the deployment directory and find where your source code fits into Capistrano's way of deploying things.

The deploy task replaces logging in to the server, getting the source, setting up any databases and restarting the servers. Run it a few times, and get used to that lazy feeling!



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

cap'ing Rails projects on servers

Walther Diechmann's picture

Hi Dan,

nice article - do you have any 'advanced' setups, like this one?

role :app, "", :primary => true, :user => "root"
role :web, ""
role :db, ""
set :gateway, "webserver.domain.tld"

set :repository, "git@{application}.git"


Because I cannot get my multistage deploy to work :)

All the blogs and articles I've come around, they all seem to focus on setups with all servers on one machine, and git somewhere entirely else (like

Best regards,