Unless you're deploying on rails, to a remote server and doing exactly what's assumed in Capistrano, the documentation is pretty unhelpful.
This tutorial will cover using Ubuntu, Git and going without Rails to deploy from another directory to another directory, all locally. You are not required to have ruby knowledge to understand this tutorial.
SSH and Git Install
If you have SSH client, server and Git, skip to Git Directory
sudo apt-get install openssh-client sudo apt-get install openssh-server sudo apt-get install git-core
Git Directory
Lets create a helloworld application
mkdir ~/helloworld cd ~/helloworld
Create a brief text file for our repo to have.
echo "hello world" | sudo tee -a ~/helloworld/HelloWorld.txt git init; git add . git commit -a -m "This is our first commit"
Sweet, now lets quickly create our remoteworld directory. This will act as a remote server location.
cd ~ git clone ~/helloworld/.git ~/remoteworld/clone
You can view the clone example.
cd ~/remoteworld/clone
Capistrano Install
sudo apt-get install capistrano
Skip this command if you wish to use rails.
sudo gem install railsless-deploy --no-rdoc --no-ri
Capistrano Setup
Now set up a Capistrano directory, this will be in charge of deploying.
mkdir ~/capistrano cd ~/capistrano capify .
Create a recipes folder.
mkdir ~/capistrano/recipes
Skip this part if you wish to use rails.
rm -f Capfile echo "require 'railsless-deploy'" | tee -a ~/capistrano/Capfile echo "load 'config/deploy'" | tee -a ~/capistrano/Capfile
Now open the config/deploy.rb. I recommend making it look something like this.
# Ruby quote ## recipes ## #require "recipes/nginx" # to only require a specific recipe # grab all recipes in the folder Dir[File.dirname(__FILE__) + '/../recipes/*.rb'].each {|file| require file } ## main config ## set :application, "remoteworld" ## source control ## set :repository, "~/helloworld/.git" set :deploy_to, "~/remoteworld/" set :scm, :git # Or: 'accurev', 'bzr', 'cvs', 'darcs', 'git', 'mercurial', 'perforce', 'subversion' or 'none' ## misc ## set :user, "andreas" # set this to whatever the remoteworld's user is set :use_sudo, false # set use sudo to false for security reasons default_run_options[:pty] = true # It solves 'pty ttl errors'. Not important. set :deploy_via, :remote_cache # it compares deployed files with remote files to only implement changed files. Saves bandwidth. ## roles ## #role :web, "your primary web-server here" #nginx, Apache, etc. role :app, "localhost" # This may be the same as your web server. #role :db, "your primary db-server here", :primary => true # This is where rails migrations will run #role :db, "your slave db-server here"
Now run this command in the same directory of your Capfile. This prepares the location for future deployments (You'll see later).
cd ~/capistrano cap deploy:setup
Now it's ready for deployment. Start deploying.
cap deploy
If you get a request for password, it's the same as the user you specified in deploy.rb above.
This is what the process looked like to me.
* executing `deploy' * executing `deploy:update' ** transaction: start * executing `deploy:update_code' updating the cached checkout on all servers executing locally: "git ls-remote ~/helloworld/.git HEAD" * executing "if [ -d ~/remoteworld/shared/cached-copy ]; then cd ~/remoteworld/shared/cached-copy && git fetch -q origin && git reset -q --hard 927b37dca3cdecb7fc2f35b08fa2a071446c9a75 && git clean -q -d -x -f; else git clone -q ~/helloworld/.git ~/remoteworld/shared/cached-copy && cd ~/remoteworld/shared/cached-copy && git checkout -q -b deploy 927b37dca3cdecb7fc2f35b08fa2a071446c9a75; fi" servers: ["localhost"] Password: [localhost] executing command command finished copying the cached version to ~/remoteworld/releases/20120112221620 * executing "cp -RPp ~/remoteworld/shared/cached-copy ~/remoteworld/releases/20120112221620 && (echo 927b37dca3cdecb7fc2f35b08fa2a071446c9a75 > ~/remoteworld/releases/20120112221620/REVISION)" servers: ["localhost"] [localhost] executing command command finished * executing `deploy:finalize_update' * executing "chmod -R g+w ~/remoteworld/releases/20120112221620" servers: ["localhost"] [localhost] executing command command finished * executing `deploy:symlink' * executing "rm -f ~/remoteworld/current && ln -s ~/remoteworld/releases/20120112221620 ~/remoteworld/current" servers: ["localhost"] [localhost] executing command command finished ** transaction: commit
Have a look at remoteworld.
cd ~/remoteworld
There's three folders; current and releases (and .git if showing hidden files). Open the current folder.
cd ~/remoteworld/current
Everything looks the same as helloworld? Yep. Now go to helloworld.
cd ~/helloworld
Lets create a new file called HelloWorld.txt in that directory. Add inside: hello crazy world.
echo "hello crazy world" | sudo tee -a ~/helloworld/HelloWorld.txt
Add new changes to the git repo
git add . git commit -a -m "this is our second commit"
Now run this command in the same directory of your Capfile.
cd ~/capistrano cap deploy
Lets look at remoteworld/current again.
cd ~/remoteworld/current
Now the file HelloWorld.txt says it's a crazy world!
Lets roll it back. Go back to the directory with the Capfile.
cd ~/capistrano cap deploy:rollback
Now back to remoteworld/current.
cd ~/remoteworld/current
The HelloWorld.txt got reverted!
What happened was that deploy:rollback sent a quick command remotely to use the previous release (hence the release folder full of releases!)
You should have now successfully installed capistrano and understand the basics.
Troubleshooting
Deploy for first time
** [localhost :: out] fatal: could not create work tree dir '/home/andreas/remoteworld/shared/cached-copy'.: Permission denied
Most likely Capistrano attempted to use sudo by default which created the directories under root, not your user. Thus, when your user attempted to create the directory, it got denied.
If Capi fails and wants sudo (notable to clean up), disable use of sudo for Capistrano.
set :use_sudo, false
no tty present and no askpass program specified
Not sure how to explain it but setting this in deploy works
default_run_options[:pty] = true
Reference: the { buckblogs :here }: Capistrano 2.1
Your own recipe
Open a new file ~/capistrano/recipes/nginx.rb
A simple task to restart nginx on command.
unless Capistrano::Configuration.respond_to?(:instance) abort "This extension requires Capistrano 2" end Capistrano::Configuration.instance.load do namespace :nginx desc <<-DESC A general description blurb can go here. \ Sends a command to target server to restart nginx. DESC task :restart, :roles => :web do sudo "/etc/init.d/nginx restart" end end # End namespace end # End Capistrano instance
It will be included via deploy.rb or individually: require "recipes/nginx"
cd ~/capistrano cap nginx:restart
More tasks (including Postgresql) at Doing Bad Things with Capistrano - Skills Matter [PDF]
My guidelines for automating repetitive commands
- Document the process. Can it be automated?
- Is a recipe already online? People usually share with Github too.
- A recipe per program is usually sufficient.
- For one command that does a lot of other commands, I usually put it in the custom recipe.
Notes
You don't need to install RubyGems or Capistrano on the remote server, as you'll usually be deploying from your local machine.
Available Tasks
Navigate to the directory where the config folder and Capfile is and run the following command to see a list of available tasks.
cap -T
There's much more here: Basic guide of deploy options
Remote
There should be created directories:
- ~/remoteworld/releases
- ~/remoteworld/current (A symlink, not quite a folder)
It's Capi's way of allowing rollback with using a symlink and releases. Capi simply links the /release with /current. Which means if something crapped, rollback to a different /release folder.
Rollback
Local - Run this immediately
cap deploy:rollback
This is a very fast task which will simply make your current symlink point to the previous release.
To re-deploy again:
cap deploy
Cleanup manually
Capi will have the last 5 releases by default. Run to cleanup
cap deploy:cleanup
Addenum
Tutorial: Deploying WordPress with Capistrano - Theme.fm
Capistrano Handbook to lower barrier of entry to understanding Capistrano. Not railsless.


