Using capistrano for drupal deployment

UPDATE: This post was written using Capistrano 1, which has since been superseded. An updated version—covering deployment of Drupal with Capistrano 2—can be found here.

It’s easy to get spoiled building rails apps. Tools like migrations make it so much easier to keep databases in sync, the way environments are managed helps considerably, and there’s Capistrano which makes rapid deployments a breeze. I miss those things when I have to work with other systems.

A few months back there had been a brief conversation about using capistrano with drupal and there are several blog posts (like this one) about using it with PHP. So today, tired of resolving folders full of uploaded files, I decided to write a quick deploy.rb to use capistrano with drupal.

I’m presuming here that we already have capistrano installed locally, that a recent version of drupal is set up on the server, and that we’re deploying to the sites folder. Within that we’re going to end up with capistrano’s standard ‘releases’ and ‘shared’ folders, but in this case ‘current’ will actually take on the domain name of our app and shared will contain ‘files’ rather than the usual system, log and pids.

So here’s how it goes. Firstly we want to define some variables

set :application, "MyApp"
set :site_name, ""
set :svn_user, "james.stewart"

# I like to have capistrano prompt me for the password.
# You can replace this with a standard assignment
set :svn_password, { Capistrano::CLI.password_prompt("SVN Password for #{svn_user}: ") }

set :deploy_to, "/home/mp_app/public_html/sites"
role :web, ""

So far, so much like a regular deploy.rb file. But if we want the app’s folder within sites to be called something other than ‘current’, we’ll need to add:

set :current_path, "#{deploy_to}/#{site_name}"

So that’s our configuration taken care of. Next we need to override a few of capistrano’s default tasks since we probably won’t be wanting to restart lighttpd/fastcgi, or change the permissions:

task :set_permissions, :except => { :no_release => true } do
  # do nothing

task :restart do
 # do nothing

task :deploy do
  # restart

And finally we want to update the setup and update_code tasks to make use of our altered directory structure.

desc <  { :no_release => true } do
  on_rollback { delete release_path, :recursive => true }



  run <  { :no_release => true } do
  run < <-CMD
    umask 02 &&
    mkdir -p #{deploy_to} #{releases_path} #{shared_path} #{shared_path}/files

Now we can save this file somewhere appropriate and deploy new versions as simply as:

% cap -f /my/path/deploy.rb deploy

People using one sites folder to run multiple applications may need to make some further alterations so their ‘shared’ and ‘releases’ folders don’t clash, but I’ll leave those as an exercise for the comments or related blog entries!

Tags: , ,


  1. What! No comments? And this is one of Google’s top hits for “drupal capistrano”

    I’m in the midst of drupal deployment hell. Is Cap still working out for you w/ Drupal?



  2. I haven’t done many drupal deployments since writing this, but my testing has continued to work. I’d love to hear of other peoples’ experiences.

  3. […] a work on process » Using capistrano for drupal deployment (tags: php automation build) […]

  4. I’m using Capistrano 2, which uses some slightly different conventions.

    Here’s most of my initial config/deploy.rb file:

    namespace :deploy do
    task :set_permissions do
    # do nothing (the permissions are probably fine)

    task :start do
    # do nothing (on the assumption that Apache is already started)

    task :restart do
    # do nothing (although it’s probably a good idea to reload apache)

    task :migrate do
    # do nothing (TODO: figure a nice Rails-style DB migration for Drupal)

    Oh, and you can just leave the :svn_password unset if you want to be prompted for it — there’s no need to write the prompting code yourself 🙂

  5. Thanks Rob. I’ve been meaning to post an update for cap 2 but hadn’t had a chance to yet.

    Any luck working out a migration style approach for drupal?

  6. For anyone following these comments, you may be interested to know that I’ve published an updated tutorial at