Capistrano

From DreamHost
Jump to: navigation, search

Capistrano automates the deployment, migration, upgrades and rollbacks of your Rails applications.

Getting Started

The instructions provided in this article or section are considered advanced.

You are expected to be knowledgeable in the UNIX shell.
Support for these instructions is not available from DreamHost tech support.
Server changes may cause this to break. Be prepared to troubleshoot this yourself if this happens.
We seriously aren't kidding about this.

This assumes you are deploying your rails application to your DreamHost server for the first time. See Ruby on Rails for more information.

Set up sub-domain

  1. Domains > Manage Domains > Add new domain / sub-domain. (This will take a while to "cook" in the background, so do it first!)
    • Enable Passenger
    • append /current/public instead of just the default web directory. (Passenger suggests "/public"; the DH default is simply the domain name.)
      • USE: newapp.yourdomain.com/current/public
      • and NOT: newapp.yourdomain.com or newapp.yourdomain.com/public
  2. After DNS allows access to your http://newapp.yourdomain.com domain, manually delete the /current/public and /current directories that were created by DH.
    • This is so that later in this tutorial, cap deploy can create a symlink to /current, allowing Capistrano and Subversion to live happily together. Thanks to topfunky.com for the troubleshooting tip!

Set up new database

  1. Goodies > MySQL (This will also take a while to "cook")
    • Optionally, follow rails conventions for MySQL and create the dbname newapp_production.
    • Setup a server for the db: mysql.yourdomain.com (Rails calls this the host).
    • Take note of the dbname, username and password you setup, as you'll need this in your database.yml


Your database.yml file should look something like this:

development:
   # [...your development settings for local machine ...]
test:
   # [...your test settings for local machine ...]
production:
  adapter: mysql
  encoding: utf8
  database: newapp_production #following rails db naming convention
  username: newapp_dbo_user
  password: newapp_dbo_pass
  host: mysql.yourdomain.com
  port: 3306  #not necessary since its the standard mysql port

Notes:

By default your database.yml often comes generated with a socket connector. Don't use socket for Dreamhost.

Replace/comment out the socket:

#socket: /var/run/mysqld/mysqld.sock 

and add the host (mysql server name setup in the panel) and port number:

host: mysql.yourdomain.com
port: 3306

I included the port here for completeness; but since DH uses the standard mysql port, its technically not necessary.

Git

Deploying to DreamHost using Capistrano & Git

Many of the instructions for using Capistrano are Subversion specific. Through much trial and error, I got Capistrano running with GitHub - given the fact that there isn't much information online, I thought I would post some tips and tricks here.

1) The first trick is that new versions of Capistrano (I installed version 2.5.8) use a syntax that DreamHost's default version of Git complains about. The solution is to compile and install Git 1.6. Fortunately, another DreamHoster has very conviniently posted straightforward instructions on doing just this here: http://blog.toppingdesign.com/2008/04/08/installing-git-on-dreamhost/

2) Now that you have Git 1.6 installed, you need to specifically tell Capistrano which version of git to use, both on the server and locally. Use these lines in your deploy.rb file to do just that:

set :scm_command, "~/packages/bin/git" #updated version of git on 
server in user directory


set :local_scm_command, "/opt/local/bin/git" #correct path to local 
git


3) Finally, you need to add the path to your installed version of Git 1.6 to your path. Typically, you would add the path to your .bash_profile file. However, this didn't seem to work for me - instead, for Capistrano I also needed a .bashrc file with your GEM PATH variable and with the path to your installed version of Git 1.6. Use these lines:


export GEM_HOME=$HOME/.gem

export GEM_PATH=$GEM_HOME:/usr/lib/ruby/gems/1.8

PATH=$PATH:~/packages/bin/

export PATH

Subversion

This step should happen after DH DNS has created your newapp.yourdomain.com and it resolves in your browser. If you do this step before that has happened, you may have to delete your subversion repository and recreate it agian.
Unless you intend to let Capistrano create your subversion repository elsewhere, you'll want to establish your subversion repository in Goodies > Subversion in DreamHost's control panel. (You can also set it up at another subversion host, if you wish. It makes sense to do it manually, if the host will not let Capistrano do it.)

Environment Configuration

Important: Read the Ruby on Rails page before you proceed, especially the "To set up Rails on a subdomain" section.

Force Production RAILS_ENV

Previously, it was recommended to uncomment the RAILS_ENV line in config/environment.rb. However, Dreamhost now defaults to 'production' environment, so this is no longer necessary. You can skip this step.

Typically, with a default rails app, the RAILS_ENV line comes commented out (#) in config/environment.rb file. Committing the environment.rb file with the line uncommented will cause havoc on your dev environment each time you update your code from the repository.

If you're using Capistrano, you can cleverly surpass this problem and force 'production' environment during deployment by add the following the task in your Capfile:

desc "Restarting after deployment"
task :after_deploy, :roles => [:app, :db, :web] do
 run "sed 's/# ENV\\[/ENV\\[/g' #{deploy_to}/current/config/environment.rb > #{deploy_to}/current/config/environment.temp"
 run "mv #{deploy_to}/current/config/environment.temp #{deploy_to}/current/config/environment.rb"
end

Fix Dispatcher Shebang!

Modify the Ruby she-bang lines. Most are fine. The ones in public/dispatch.* are wrong. Change them to:

 #!/usr/bin/env ruby

Sometimes this is not correct. To make sure login the shell and try a "whereis ruby" or run "./dispatch.fcgi" yourself.

Fix .htaccess to use Dispatcher

In public/.htaccess, change the RewriteRule for the dispatcher to use the FastCGI dispatcher instead:

RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]

Add these rules immediately after RewriteEngine On to display a maintenance page if it exists on the file system:

RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteCond %{SCRIPT_FILENAME} !^(.+).(gif|jpg|css|js|swf)$
RewriteRule ^.*$ /system/maintenance.html [L]

Automate Deployment with Capistrano ("capify")

From your RAILS_ROOT, execute the following commands:

$ capify .

The above will create the two files ('Capfile' and 'deploy.rb') inside your rails root, that Capistrano uses to do deployment. The output should look something like this:

[add] writing `./Capfile'
[add] writing `./config/deploy.rb'
[done] capified!
$ svn add Capfile config/deploy.rb

The above line adds the new Capistrano files to your subversion repository.

Edit config/deploy.rb, setting :application and :repository properly. All roles should point to your newly created web host. :deploy_to should point to the top-level of the web directory you set up earlier (NOTE: leave current/public off the end). On DreamHost's shared hosts, sudo can't be used to restart the app. So set :use_sudo to false. Set :deploy_via to :export so as not to create a .svn in your world-accessible directory.

Your config/deploy.rb should resemble:

set :user, 'dhuser'  # Your dreamhost account's username
set :domain, 'servername.dreamhost.com'  # Dreamhost servername where your account is located 
set :project, 'myapp_name_from_repository'  # Your application as its called in the repository
set :application, 'myapp.mydomain.com'  # Your app's location (domain or sub-domain name as setup in panel)
set :applicationdir, "/home/#{user}/#{application}"  # The standard Dreamhost setup

# version control config
set :scm_username, 'YOUR_SVN_USERNAME'
set :scm_password, 'YOUR_SVN_PASSWORD'
set :repository, "http://svn.my_subversion_domain/#{project}/trunk/"

# roles (servers)
role :web, domain
role :app, domain
role :db,  domain, :primary => true

# deploy config
set :deploy_to, applicationdir
set :deploy_via, :export

# additional settings
default_run_options[:pty] = true  # Forgo errors when deploying from windows
#ssh_options[:keys] = %w(/Path/To/id_rsa)            # If you are using ssh_keys
set :chmod755, "app config db lib public vendor script script/* public/disp*"
set :use_sudo, false

Note that the db role specifies where migrations should be run, not where the database is located. That's why the domain should be the one where you have shell access, not your database's domain.

If you've configured a SSH public/private key, you may set the ssh_options[:keys] variable to prevent Capistrano from asking for your password.

If you are using git for source control, be sure to add:

set :scm, 'git'
set :repository,  "git@github.com:your_username/your_project.git"
set :deploy_via, :remote_cache
set :git_enable_submodules, 1 # if you have vendored rails
set :branch, 'master'
set :git_shallow_clone, 1
set :scm_verbose, true

Deployment with Capistrano

NOTE: Commit the changes (covered above) in environment, config, and .htaccess / dispatch.* files to your subversion repository prior to deploying.

Prepare deploy environment

First setup server environment by running:

cap deploy:setup

Note: cap deploy:setup creates the releases and shared folders. Running cap migrate after might give you a file not found bash error as capistrano tries to cd the current folder; never mind this and simply skip to cap deploy.

If your repository and config/deploy.rb are set up properly, cap deploy will create a current symlink to the active release folder after exporting it from your repository.

Deploy

After setting up the environment, run a "cold" deployment (first time only):

cap deploy:cold 

From then on, to deploy new versions, run:

cap deploy
# or:
cap deploy:migrate

It might go without saying, but you'll need the command line version of Subversion installed on your development server for the above commands to work.

Maintenance via Capistrano

To revert instantly from a disastrous deployment, run:

cap deploy:rollback

If you need to stop for serious maintenance:

cap deploy:web:disable

Run this when you're ready to face the world again:

cap deploy:web:enable

Update your production server with latest changes from svn:

cap deploy
#or: more explicitly...
cap deploy:stop
cap deploy:update
cap deploy:start

Miscellaneous Tasks

To see the tasks available to you, from your RAILS_ROOT run:

$ cap -T

Will give you a listing of all the tasks available. Run the following for a specific task to get the description:

$ cap -e [taskname]

Keep Generated Files Between Deployments

If your Rails app stores any files on the file system, these aren't kept in SVN so they will need to be kept such that they aren't lost when you re-deploy a new version. The "shared" directory is intended for this, and you can symlink files that you store under "shared" to where they belong within your deployment. You can use a Capistrano event hook to make a task for this in the Capfile so that this works transparently every time you re-deploy.

In this example, files that you want to appear at public/files/uploads are stored under shared/uploads:

desc "Link shared files"
task :before_symlink do
  run "rm -drf #{release_path}/public/files/uploads"
  run "ln -s #{shared_path}/uploads #{release_path}/public/files/uploads"
end

The directory will now act like it's part of the current deployment, but won't be lost when you re-deploy.

Gotchas

Setting up the Migrations

Be sure to use the username and password from the "production" section of your database.yml file to create a new user in the Dreamhost panel: Goodies/Manage MySQL. Check everything is running correctly by running cap deploy:migrations from your local computer, or ssh into the server and run

rake RAILS_ENV=production db:migrate --trace

Default shell

Note that Capistrano assumes your default shell is bash (or perhaps some other sh variant). If you get "if syntax" errors when attempting to deploy, this may be the problem. To fix it, log into the Dreamhost control panel and change your shell to bash.

Freezing Rails vs. Third party code

If you're freezing Rails for deployment (as is wise following the aborted debut of Rails 1.1 at DreamHost) you will need to take special precautions. One way is to set svn:externals on vendor/ to rails http://dev.rubyonrails.org/svn/rails/tags/rel_1-1-0 (for Rails 1.0) instead of running rake freeze_gems. The downside is that your deployments will depend on dev.rubyonrails.org being reachable. Tracking your third party dependencies in your own repositories avoids this problem.

cap deploy gets stuck 'subversion is asking for a password'

You need to make sure the account you’re using with Capistrano (i.e. your dreamhost account) can access your Subversion repository from the app server where the cap script is running. The solution seems to be to SSH into your dreamhost server and svn co your_repos into a temp directory. It’ll prompt you for the username and password, and once you’ve entered it successfully, it’ll remember it. Then you’ll be able to deploy without any problems.

"svn export" results in 'Killed by signal 15'

If you are pulling your code from your local environment using svn+ssh:// URLs, you will likely get a "Killed by signal 15" error message:

Try running this command from your DreamHost server:

svn list svn+ssh://username@offsite.com/abs/path/to/svn/repos/rails_apps/test_foo
foo
bar
config
...

Killed by signal 15

To get around this, you can change the ":deploy_via, :export" to ":deploy_via, :copy" which will do the local checkout and then push a tar.gz file to the DH server. This also works if you're not using DH svn server, or your svn repository is not accessible over the internet (ie: behind a firewall).

Resources

SwitchTower

Capistrano was known as SwitchTower until March 2006. Graeme Mathieson's excellent quick-start guide for SwitchTower (the principal source for this article) can be found here: Using SwitchTower with Ruby on Rails and DreamHost.