[section_title title=”Setting up your development environment”]

The Rails Application

Obviously you will need an application to deploy. If you already have an application ready to be deployed then go on to the next step below. If you don’t already have an application or would not like to mess with your actual application just yet but would like to test out Capistrano, then do the following to create a simple “hello Capistrano” rails application.

mkdir hello_capistrano
rails hello_capistrano

Running the above two commands will give you base application to work with.

Installing Capistrano

This is probably the easiest step, since RubyGems does all the work for you. To install Capistrano execute gem install capistrano, and you will have Capistrano ready for your service.

Setting up Your Application and First Deployment

This is the part that will require tinkering with your application and configuration files. I will be calling my application BitGurus, change this to whatever you are calling your application.

First let’s generate the required files for Capistrano; or how RoR people like to put it, let’s capistranize! While inside your application’s root directory, execute the following command.

[test_user@dreamer dev_site]$ cap --apply-to . BitGurus
      exists  config
      create  config/deploy.rb
      exists  lib/tasks
      create  lib/tasks/capistrano.rake
[test_user@dreamer dev_site]$

In addition to other files, this will generate config/deploy.rb. deploy.rb contains the configuration and basic tasks for your deployment needs. Go ahead and open this file in your favorite editor because we need to make a few changes in there.

  1. Set the repository URL: set :repository, "svn+ssh://<your_user_name>@<your_domain.com>/home/<your_user_name>/svn_repo/trunk".
  2. Set the locations of the web, app, and db roles to your domain. I only use the :web and :app roles but I have everything set to “www.thebitguru.com”.
  3. Uncomment the deploy_set set statement and change it to set the appropriate deployment location. set :deploy_to, "/home/<your_user_name>/apps/#{application}"
  4. If your user is different that your local machine’s user name then uncomment and set the user:set :user, ““
  5. Uncomment the ssh_options[:keys] and set it to the generate private key: ssh_options[:keys] = %w(/home/<your_user_name>/.ssh/id_rsa).
  6. Add another set command to set the pass phrase for the public/private key pair that you generated on the remote server: set :svn_passphrase, "whatEverPassphraseYouUsed"
  7. Finally, we have to override that default restart task since that doesn’t work for Site5. Add the following code to the bottom of this file.
desc "Restart the web server. Overrides the default task for Site5 use."
task :restart, :roles => :app do
  #run "killall -q dispatch.fcgi"
  run "chmod 755 #{current_path}/public/dispatch.fcgi"
  run "touch #{current_path}/public/dispatch.fcgi"
end

Those are all the configuration changes we needed to make, so go ahead and save the file and exit the editor.

The commands from here on assume that you are in an ssh-agent initiated shell. Don’t worry if you are not, you will just have to type in the passwords multiple times. You can refer back to the SSH section if you are lost.

Before we go any further, let’s quickly look at what Capistrano is going to do. When you tell Capistrano to deploy, it will assume that the specified SVN repository has the latest code. So, it will not check-in your code to the repository, instead, by default, it will checkout the HEAD (i.e. the last checked-in) revision and put that in all the specified servers. What this means for you is that you will have to manually check-in your latest code into the trunk before doing a deployment. This is logical and you would be doing that anyways but I still wanted to point this out.

There are two ways you can import your non-versioned code into the newly created SVN repository. The first one is to use the svn import command, delete the directory and check-out the checked-in revision, or you can run the following commands to do an in-place ‘import’. I am also ignoring the log directory and setting the ‘svn:ignore’ property on the main folder so we ignore the ‘log’ and ‘tmp’ directories. You have to separate tmp and log using a new line, so, make sure that you press enter after tmp.

[aficionado@dreamer dev_site]$ svn co svn+ssh://[email protected]/home/bitgurus/svn_repo/trunk .
Checked out revision 1.
[aficionado@dreamer dev_site]$ svn status | awk '{print $2}' | xargs svn add
A         ...
A         ... SVN prints out each file / directory that is add.
A         ...
[aficionado@dreamer dev_site]$ svn rm log
[aficionado@dreamer dev_site]$ svn propset 'svn:ignore' "tmp
log" .
[aficionado@dreamer dev_site]$ svn commit -m "Initial code import"
Adding         ...
Adding         ... SVN prints out each file / directory that is add.
Adding         ...
Transmitting file data ..............................................
Committed revision 2.
[aficionado@dreamer dev_site]$ mkdir log
[aficionado@dreamer dev_site]$

If you are following the instructions step-by-step then this will bring your repository to revision 2. Note that since I was using ssh-agent, I didn’t have to type in a single password.

Now that we have the code checked-in and -out, let’s tell Capistrano to do the initial setup; to do this, run the following commands while in your application’s main directory.

Originally you would have had to use a command like rake remote:exec ACTION=setup, but this is not necessary any more; now you can just run cap setup.

[aficionado@dreamer dev_site]$ cap setup
    loading configuration /usr/lib/ruby/gems/1.8/gems/capistrano-1.2.0/lib/capistrano/recipes/standard.rb
    loading configuration ./config/deploy.rb
  * executing task setup
  * executing "mkdir -p -m 775 /home/bitgurus/apps/bit_gurus/releases /home/bitgurus/apps/bit_gurus/shared/system &&\n    mkdir -p -m 777 /home/bitgurus/apps/bit_gurus/shared/log &&\n    mkdir -p -m 777 /home/bitgurus/apps/bit_gurus/shared/pids"
    servers: ["www.bitgurus.com"]
    [www.bitgurus.com] executing command
    command finished
[aficionado@dreamer dev_site]$

Great, everything worked as expected. Let’s do the actual deployment!

[aficionado@dreamer dev_site]$ cap deploy
(in /storage/important/www/rails/bitgurus.com/dev_site)
/
    loading configuration /usr/lib/ruby/gems/1.8/gems/capistrano-1.2.0/lib/capistrano/recipes/standard.rb
    loading configuration ./config/deploy.rb
  * executing task deploy
  * executing task update
 ** transaction: start
  * executing task update_code
  * querying latest revision...
  * executing "if [[ ! -d /home/bitgurus/apps/bit_gurus/releases/20061120061800 ]]; then\n              svn co  -q -r2 svn+ssh://[email protected]/home/bitgurus/svn_repo/trunk /home/bitgurus/apps/bit_gurus/releases/20061120061800 &&\n              (test -e /home/bitgurus/apps/bit_gurus/revisions.log || (touch /home/bitgurus/apps/bit_gurus/revisions.log && chmod 666 /home/bitgurus/apps/bit_gurus/revisions.log)) && echo `date +\"%Y-%m-%d %H:%M:%S\"` $USER 2 20061120061800 >> /home/bitgurus/apps/bit_gurus/revisions.log;\n            fi"
    servers: ["www.bitgurus.com"]
    [www.bitgurus.com] executing command
 ** [out :: www.bitgurus.com] Enter passphrase for key '/home/bitgurus/.ssh/id_rsa':
 ** [out :: www.bitgurus.com] subversion needs your key's passphrase
 ** [out :: www.bitgurus.com] Enter passphrase for key '/home/bitgurus/.ssh/id_rsa':
 ** [out :: www.bitgurus.com] subversion needs your key's passphrase
    command finished
  * executing "rm -rf /home/bitgurus/apps/bit_gurus/releases/20061120061800/log /home/bitgurus/apps/bit_gurus/releases/20061120061800/public/system &&\n    ln -nfs /home/bitgurus/apps/bit_gurus/shared/log /home/bitgurus/apps/bit_gurus/releases/20061120061800/log &&\n    ln -nfs /home/bitgurus/apps/bit_gurus/shared/system /home/bitgurus/apps/bit_gurus/releases/20061120061800/public/system"
    servers: ["www.bitgurus.com"]
    [www.bitgurus.com] executing command
    command finished
  * executing "test -d /home/bitgurus/apps/bit_gurus/shared/pids && \n    rm -rf /home/bitgurus/apps/bit_gurus/releases/20061120061800/tmp/pids && \n    ln -nfs /home/bitgurus/apps/bit_gurus/shared/pids /home/bitgurus/apps/bit_gurus/releases/20061120061800/tmp/pids; true"
    servers: ["www.bitgurus.com"]
    [www.bitgurus.com] executing command
    command finished
  * executing task symlink
  * executing "ls -x1 /home/bitgurus/apps/bit_gurus/releases"
    servers: ["www.bitgurus.com"]
    [www.bitgurus.com] executing command
    command finished
  * executing "ln -nfs /home/bitgurus/apps/bit_gurus/releases/20061120061800 /home/bitgurus/apps/bit_gurus/current"
    servers: ["www.bitgurus.com"]
    [www.bitgurus.com] executing command
    command finished
 ** transaction: commit
  * executing task restart
  * executing "chmod 755 /home/bitgurus/apps/bit_gurus/current/public/dispatch.fcgi"
    servers: ["www.bitgurus.com"]
    [www.bitgurus.com] executing command
    command finished
  * executing "touch /home/bitgurus/apps/bit_gurus/current/public/dispatch.fcgi"
    servers: ["www.bitgurus.com"]
    [www.bitgurus.com] executing command
    command finished
[aficionado@dreamer dev_site]$

And… wala! Our application is deployed! Well, not so fast, there are still a few things that we need to change.