Deploying With Capistrano Without Rails

By Ryan Florence, published 2010-07-27

Part of the issue Git Your Act and Deployment Together.

Developing web apps with Ruby on Rails has a lot of conveniences developers are almost smug about. Capistrano, though not a part of rails directly, I think belongs in the category. After using it once I was sold. What is it? Straight from capify.org:

Simply put, Capistrano is a tool for automating tasks on one or more remote servers. It executes commands in parallel on all targeted machines, and provides a mechanism for rolling back changes across multiple machines. It is ideal for anyone doing any kind of system administration, either professionally or incidentally.

Capistrano runs on your workstation, not the server, and is arguably the best deployment program out there. However, it’s completely smitten by Rails. Enter railsless-deploy, a gem by Lee Hambley. From the gem’s README:

If you want to get the most out of Capistrano and you do not want to have to deal with the railsisms that ship by default, this is the gem for you.

We’re going to see just how easy, and awesome, capistrano and railsless-deploy are together for any website. This is a very quick how-to, getting you over the hump with Capistrano. For more in depth resources, check out the links at the end of this article.

What you will need

Some of this is from capify.org

  1. Ruby
  2. SSH access to a server with a POSIX-compatible shell installed
  3. Access to your server with a public key

This is the setup I’m on:

  1. Workstation: Mac OS X 10.6, Ruby 1.8.7, git
  2. Server: Linode, Ubuntu Hardy VPS

Installation

Many capistrano investigators think it’s a server-side program. It’s actually installed on your workstation, not the server. Like all gems, open the terminal and install them:

$ gem install capistrano
$ gem install railsless-deploy

Create and configure the test website

Here are a few commands to make a silly test site.

$ mkdir test
$ cd test
$ echo "Hi and stuff" > index.html

Capistrano requires your site to be a repository of some sort, I’m going to use git.

$ git init

Capify your site

Hopefully none of that was frightening. Now the Capistrano stuff shows up. First you “capify” your site with a simple capify and then a path.

$ capify .

This will create a few files for you: Capfile, config/, config/deploy.rb. Now we do some of the railsless-deploy stuff. Open up the Capfile and change it to:

require 'rubygems'
require 'railsless-deploy'
load 'config/deploy.rb' if respond_to?(:namespace)

The Capfile does little more than tell capistrano where the deployment “recipe” is. Open up the recipe in config/deploy.rb and paste this into it, replacing my stuff like “example.com” with your own information, of course:

# replace these with your server's information
set :domain,  "example.com"
set :user,    "user"

# name this the same thing as the directory on your server
set :application, "test"

# use your local repository as the source
set :repository, "file://#{File.expand_path('.')}"

# or use a hosted repository
#set :repository, "ssh://user@example.com/~/git/test.git"

server "#{domain}", :app, :web, :db, :primary => true

set :deploy_via, :copy
set :copy_exclude, [".git", ".DS_Store"]
set :scm, :git
set :branch, "master"
# set this path to be correct on yoru server
set :deploy_to, "/home/#{user}/public_html/#{application}"
set :use_sudo, false
set :keep_releases, 2
set :git_shallow_clone, 1

ssh_options[:paranoid] = false

# this tells capistrano what to do when you deploy
namespace :deploy do

  desc <<-DESC
  A macro-task that updates the code and fixes the symlink.
  DESC
  task :default do
    transaction do
      update_code
      symlink
    end
  end

  task :update_code, :except => { :no_release => true } do
    on_rollback { run "rm -rf #{release_path}; true" }
    strategy.deploy!
  end

  task :after_deploy do
    cleanup
  end

end

Now go ahead and commit everything to git

$ git add .
$ git commit -m 'first commit'

Setup the server and deploy

Before we go any further with Capistrano there are a couple things that need to happen on the server. First, you need a directory for the site to be deployed to. In deploy.rb you specified a path for deploy_to. Make sure that exists:

$ ssh user@example.com
$ mkdir /home/user/public_html/test

Now go back to your workstation. Capistrano sets up the server for you. Run this command:

$ cap deploy:setup

It’s going to run several tasks on the server. If you’ve still got the server shell open, list the directory of your site and you’ll see:

test/
  releases/
  shared/

Now we are ready to deploy:

$ cap deploy

Once that finishes, go again to your server shell and list the directory. You’ll see something like:

test/
  current/
  releases/
  shared/

I said earlier there were a couple things to do on the server. This is the second, you need to point your webserver document root to the current directory. In my example, using apache, I’d set it to /home/user/public_html/test/current. Of course, if your web root is a sub folder of your repo then you’d do ../current/public or whatever.

Congratulations! You’ve now deployed the site.

Deploying the next version

On your workstation, make some changes to index.html, commit the changes to git, and then run the deploy command again.

$ echo "I am new text" > index.html
$ git commit -a -m 'updated stuff'
$ cap deploy

How easy was that? Now get on the server and check out the releases directory, it’ll look something like

$ ls releases
20100727171750  20100727172413

In your deploy.rb you can specify how many releases to keep around. This is handy because you may need to rollback if you release a steaming pile on accident.

Rolling back a release

$ cap deploy:rollback

This will go on the server, point the current symlink to the release before last and remove the last release completely. Headaches and major disasters averted.

Now what?

For most sites, this is enough. But for other sites, like a django app or a wordpress install, you may want to run some other tasks on the server. Here are a few links I think are good. If you know of some other resources, comment and I’ll add them:

Hi, I'm Ryan!

Location:
South Jordan, UT
Github:
rpflorence
Twitter:
ryanflorence
Freenode:
rpflo

About Me

I'm a front-end web developer from Salt Lake City, Utah and have been creating websites since the early 90's. I like making awesome user experiences and leaving behind maintainable code. I'm active in the JavaScript community writing plugins, contributing to popular JavaScript libraries, speaking at conferences & meet-ups, and writing about it on the web. I work as the JavaScript guy at Instructure.