Deploying Your Application to Multiple Environments with Capistrano

Problem

Contributed by: Ben Bleything

You want to use Capistrano to deploy your application, but you need to be able to deploy to more than one environment.

Solution

NOTE

For this recipe, we'll be assuming you have a production and a staging environment.

Capistrano is extremely flexible; it gives you a great deal of control over your deployment. To take advantage of this to accomplish your goals, set up your deployment environments inside tasks:

config/deploy.rb:

set :application, 'example'
set :repository, 'http://svn.example.com/example/trunk'
set :deploy_to, '/var/www/example'
set :user, 'vlad'
task :production do
 role :web, 'www.example.com'
 role :app, 'www.example.com'
 role :db, 'www.example.com', :primary => true end task :staging do
 role :web, 'staging.example.com'
 role :app, 'staging.example.com'
 role :db, 'staging.example.com', :primary => true end

Once that's in place, you can perform actions in your desired environment by chaining commands together:

$ cap staging setup
$ cap production setup deploy

Discussion

We've only really scratched the surface in this solution. By setting your environment in tasks and then chaining them together, you can create complex deployment scenarios. For instance, to initialize your environments once you've got them configured, this is perfectly valid:

$ cap staging setup deploy production setup deploy

If your environment is simpler, you may be able to simplify the deployment. For instance, if your staging environment is just another directory on the production server, you can do this:

config/deploy.rb:

set :application, 'example'
set :repository, 'http://svn.example.com/example/trunk'
set :web, 'example.com'
set :app, 'example.com'
set :db, 'example.com', :primary => true set :deploy_to, '/var/www/production'
set :user, 'vlad'
task :stage do
 set :deploy_to '/var/www/staging'
 deploy end

Then run your new task:

$ cap stage

To accommodate alternate environments, you may want to create new environments in your Rails application. This is as simple as cloning config/environments/production.rb:

$ cp config/environments/production.rb config/environments/staging.rb

and adding a new section to your database.yml:

config/database.yml:

common: &common
 adapter: sqlite development:
 database: db/dev.sqlite
 <<: *common test:
 database: db/test.sqlite
 <<: *common production:
 database: db/production.sqlite
 <<: *common
staging:
 database: db/staging.sqlite
 <<: *common

See Also