A little over a year ago I wrote up some instructions for deploying drupal sites using capistrano. It’s proved a popular entry, still getting a good bit of traffic, but in the time since I wrote it Capistrano 2 has joined us and my techniques have moved on, so it seemed high time I updated the instructions with some new ones.
As before, I’m going to presume that anyone reading this already has capistrano installed and has shell access to their server. If you need help with the former, I’d recommend stopping by the Capistrano website, and for the latter you should probably talk to your hosting company.
My approach is to keep each site’s assets (modules, themes, etc) within that site’s folder, and then store each site in version control (git or subversion). In common with capistrano-based rails deployments, I then have the site’s files and images stored in a shared folder and symlinked into the site, so that they can be preserved between deployments.
To get started go into the folder for the site you want to be able to deploy (eg. /path/to/drupal/sites/mysite.com) and type at the command line:
mkdir config
capify .That will create the basic files for deployment, which you will then need to edit with your configuration details. I start by opening the file config/deploy.rb and deleting everything in it, so as to start with a blank slate. I then put in some overrides to capistrano’s default deployment methods so that they work better with drupal:
set :asset_folders, %W(images files) namespace :deploy do desc "Link the asset folders from the shared folder into our site" task :finalize_update, :except => { :no_release => true } do logger.info 'finalizing update with custom method' run "chmod -R g+w #{latest_release}" if fetch(:group_writable, true) asset_folders.each do |asset| run "rm -rf #{release_path}/#{asset}" run "ln -nfs #{shared_path}/#{asset} #{release_path}/#{asset}" end end desc "Set up the expected application directory structure on all boxes" task :setup, :except => { :no_release => true } do run <<-CMD umask 02 && mkdir -p #{deploy_to} #{releases_path} #{shared_path} CMD asset_folders.each do |asset| run "mkdir #{shared_path}/#{asset}" end end task :set_permissions, :except => { :no_release => true } do # do nothing end task :restart do # do nothing end end
You then need to set some basic configuration, so also in deploy.rb place:
set :deploy_to, '/path/to/your/drupal/sites' # Make sure this is the domain name of your app as it is # what your sites folder will be named set :site_name, 'staging.scodigo.com' role :web, "your.server.com" set :current_path, "#{deploy_to}/#{site_name}" set :shared_path, "#{deploy_to}/shared/#{site_name}" set :repository, "svn://your.svn.com/path/to/repos/trunk"
With that in place you’re all ready to go. But there was an extra step I decided to add this time around. Since I am frequently setting up new staging/test sites and often need to upgrade them to new versions of drupal, I wanted to be able to install and update the drupal files using capistrano.
To do that, I wrote a recipe that will grab the tarball for a given release, unpack it and install it, without wiping out an existing sites folder. To add that you will need to put the following code into your deploy.rb file:
namespace :drupal do desc <<-DESC Grab the specified version of drupal and install it This presumes that the variables drupal_version and drupal_path have been set DESC task :install do run "cd #{shared_path} && curl -O http://ftp.drupal.org/files/projects/drupal-#{drupal_version}.tar.gz" run "cd #{shared_path} && tar xzvf drupal-#{drupal_version}.tar.gz" run "rm -rf #{shared_path}/drupal-#{drupal_version}/sites" run "cd #{drupal_path} && rm -rf !(sites)" run "mv #{shared_path}/drupal-#{drupal_version}/* #{drupal_path}" run "mv #{shared_path}/drupal-#{drupal_version}/.htaccess #{drupal_path}/.htaccess" run "rm -rf #{shared_path}/drupal-#{drupal_version}" end end after "deploy:setup", "drupal:install" set :drupal_path, File.join(deploy_to, '../') set :drupal_version, "5.8" # Or whatever version you want to install
(You can download a copy of the combined deploy.rb file here or view it as a pastie here)
Now, to set up your drupal site you just need to change directory to your site and type and command line:
cap deploy:setup
and to deploy a new version:
cap deploy
In practice, I tend to use these techniques in combination with the Capistrano Multistage extension, so that I can deploy a site to a staging server first, and then a production server. I’d highly recommend that approach, but for now will leave it as an exercise for the reader.
Please note that this technique is also designed to support a multi-site drupal set up, but hasn’t been extensively tested in that context. It should work, but no guarantees!
If you’ve encountered Ruby primarily through Rails and know it chiefly as an elegant tool for writing web applications it’s easy to miss its longer history as a tool for systems administration. Before Rails made Ruby the language-du-jour sysadmins bore much of the responsibility for keeping it alive, with the result that it has a suite of libraries helpful for server monitoring and a range of other administrative tasks.
