In this example we're going to deploy an application from one vagrant box to another with capistrano. We will set up staging and production servers to deploy our application to. The deployment will take place from a dev machine. For more information visit Capistrano page.


Prerequisites


First of all, make sure all three servers have access to GitHub repository so add their SSH keys to GitHub repository.


You need to do these on your deployment machine only.


Install ruby


$ sudo add-apt-repository -y ppa:brightbox/ruby-ng
$ sudo apt-get update -y
$ sudo apt-get install -y ruby2.2

Install capistrano


$ sudo gem install capistrano
$ sudo gem install capistrano-ext

Install bundler


$ sudo gem install bundler

Staging and Production servers


These are the important Vagrantfile information. Vagrant login by default is vagrant:vagrant.


private_network IP: 192.168.99.40 # Staging
private_network IP: 192.168.99.50 # Production
synced_folder: /srv/www

Dev environment


This is where we deploy our application from. I assume that you already have cloned your GIT repository on this machine and SSH setup. Our test application is called football.


SSH authorized_keys


If you don't do this on dev server, everytime you try to deploy your application to remote servers staging and production, you'll be asked to enter remote servers' password which is vagrant in our case. If you don't have ~/.ssh/id_rsa.pub in your system yet, run ssh-keygen -t rsa command to create one.


$ cat ~/.ssh/id_rsa.pub | ssh vagrant@192.168.99.40 'cat >> /home/vagrant/.ssh/authorized_keys'
$ cat ~/.ssh/id_rsa.pub | ssh vagrant@192.168.99.50 'cat >> /home/vagrant/.ssh/authorized_keys'

Bundler


Manually create Gemfile. For more information, visit Bundler page.


$ cd /projects/football
football$ cat > Gemfile <<EOD
source 'https://rubygems.org'

gem 'capistrano', '~> 3.8'
EOD

Install Gemfile bundles which will create "Gemfile.lock" under project root.


football$ bundle install

Fetching gem metadata from https://rubygems.org/..........
Fetching version metadata from https://rubygems.org/.
Resolving dependencies...
Installing rake 12.0.0
Using net-ssh 4.1.0
Using i18n 0.8.1
Using bundler 1.14.6
Using net-scp 1.2.1
Using sshkit 1.13.1
Using airbrussh 1.1.2
Using capistrano 3.8.0
Bundle complete! 1 Gemfile dependency, 8 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.

Capistrano


Activation below will create necessary files and folder for you to work on. Files will have some dummy configurations information inside. We'll replace all with our configurations later on. For more information, visit configuration page.


$ cd /projects/football
football$ cap install

mkdir -p config/deploy
[created] config/deploy.rb
[created] config/deploy/staging.rb
[created] config/deploy/production.rb
mkdir -p lib/capistrano/tasks
[created] create Capfile already exists
Capified

Lets change the content of some files. You can create a .gitignore file to place log and lib inside.


Capfile


# Load plugins.

require "capistrano/setup"
require "capistrano/deploy"
require "capistrano/scm/git"

install_plugin Capistrano::SCM::Git

deploy.rb


# Locked capistrano version.
lock "3.8.0"

# The name of the application.
set :application, "football"

# The path on the remote server where the application will be deployed.
# This must be owned and have RW permissions by/for "vagrant" user.
set :deploy_to, "/srv/www/#{fetch(:application)}"

# The application repository.
set :repo_url, "git@github.com:Inanzzz/football.git"

# Asks branch to deploy.
ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp

# Output styling.
set :format, :airbrussh

# Amount of releases to keep.
set :keep_releases, 5

staging.rb


# The settings for remote staging server.
server "192.168.99.40", user: "vagrant", roles: %w{app db web}

production.rb


# The settings for remote production server.
server "192.168.99.50", user: "vagrant", roles: %w{app db web}

Deployment


We have staging and production environments to deploy our application to. The very first deployment will create football folder under /srv/www path. This path will contain example files and folders below on both environments.


$ ls -l /srv/www/football/
total 8
lrwxr-xr-x 1 vagrant vagrant 41 Apr 7 2017 current -> /srv/www/football/releases/20170407215525
drwxr-xr-x 1 vagrant vagrant 102 Apr 7 2017 releases
drwxr-xr-x 1 vagrant vagrant 408 Apr 7 2017 repo
-rw-r--r-- 1 vagrant vagrant 106 Apr 7 2017 revisions.log
drwxr-xr-x 1 vagrant vagrant 68 Apr 7 2017 shared


For more information, visit structure page.


Deploy


Add --trace flag to bundle exec cap .... deploy --trace command for detailed output. You'll be prompted to enter password for remote vagrant box so type vagrant. You'll also be prompted to enter which branch you want to deploy.


$ cd /projects/football
football$ bundle exec cap {staging|production} deploy

Output


00:00 git:wrapper
01 mkdir -p /tmp
vagrant@192.168.99.40's password:
✔ 01 vagrant@192.168.99.40 10.360s
Uploading /tmp/git-ssh-football-staging-vagrant.sh 100.0%
02 chmod 700 /tmp/git-ssh-football-staging-vagrant.sh
✔ 02 vagrant@192.168.99.40 0.005s
Please enter branch (develop): master
00:14 git:check
01 git ls-remote git@github.com:Inanzzz/football.git HEAD
01 11d9954321c5d83c9039d35336cdefdb87753333 HEAD
✔ 01 vagrant@192.168.99.40 1.674s
00:15 deploy:check:directories
01 mkdir -p /srv/www/football/shared /srv/www/football/releases
✔ 01 vagrant@192.168.99.40 0.006s
00:15 git:clone
The repository mirror is at /srv/www/football/repo
00:15 git:update
01 git remote set-url origin git@github.com:Inanzzz/football.git
✔ 01 vagrant@192.168.99.40 0.016s
02 git remote update --prune
02 Fetching origin
02 From github.com:Inanzzz/football
02 33ea35c..99d9954 develop -> develop
✔ 02 vagrant@192.168.99.40 1.516s
00:17 git:create_release
01 mkdir -p /srv/www/football/releases/20170407233938
✔ 01 vagrant@192.168.99.40 0.009s
02 git archive master | /usr/bin/env tar -x -f - -C /srv/www/football/releases/20170407233938
✔ 02 vagrant@192.168.99.40 0.128s
00:17 deploy:set_current_revision
01 echo "9n3426851299e4bac6f1b51729b623859c70ef90" >> REVISION
✔ 01 vagrant@192.168.99.40 0.017s
00:17 deploy:symlink:release
01 ln -s /srv/www/football/releases/20170407233938 /srv/www/football/releases/current
✔ 01 vagrant@192.168.99.40 0.007s
02 mv /srv/www/football/releases/current /srv/www/football
✔ 02 vagrant@192.168.99.40 0.013s
00:17 deploy:log_revision
01 echo "Branch master (at 9n3426851299e4bac6f1b51729b623859c70ef90) deployed as release 20170407233938 by vagrant" >> /srv/www/footb…
✔ 01 vagrant@192.168.99.40 0.012s

Rollback


If you deployed a bad code, you can easily go back to previous release. The output below shows the current status before rollback process.


vagrant@prod:~$ ls -lt /srv/www/football/
lrwxr-xr-x 1 vagrant vagrant 41 Apr 8 2017 current -> /srv/www/football/releases/20170408032202
drwxr-xr-x 1 vagrant vagrant 238 Apr 8 2017 releases
-rw-r--r-- 1 vagrant vagrant 636 Apr 8 2017 revisions.log
drwxr-xr-x 1 vagrant vagrant 408 Apr 8 2017 repo
drwxr-xr-x 1 vagrant vagrant 68 Apr 7 21:58 shared

vagrant@prod:~$ ls -lt /srv/www/football/releases/
drwxr-xr-x 1 vagrant vagrant 476 Apr 8 2017 20170408032202
drwxr-xr-x 1 vagrant vagrant 68 Apr 8 2017 20170408032150
drwxr-xr-x 1 vagrant vagrant 68 Apr 8 2017 20170408030058
drwxr-xr-x 1 vagrant vagrant 476 Apr 8 2017 20170408024838
drwxr-xr-x 1 vagrant vagrant 68 Apr 8 2017 20170408024828

Let's rollback.


$ bundle exec cap production deploy:rollback

The output below will tell you what rollback has done.


lrwxr-xr-x 1 vagrant vagrant    41 Apr  8  2017 current -> /srv/www/football/releases/20170408032150
drwxr-xr-x 1 vagrant vagrant 204 Apr 8 2017 releases
-rw-r--r-- 1 vagrant vagrant 682 Apr 8 2017 revisions.log
-rw-r--r-- 1 vagrant vagrant 40091 Apr 8 2017 rolled-back-release-20170408032202.tar.gz
drwxr-xr-x 1 vagrant vagrant 408 Apr 8 2017 repo
drwxr-xr-x 1 vagrant vagrant 68 Apr 7 21:58 shared

vagrant@prod:~$ ls -lt /srv/www/football/releases/
drwxr-xr-x 1 vagrant vagrant 68 Apr 8 2017 20170408032150
drwxr-xr-x 1 vagrant vagrant 68 Apr 8 2017 20170408030058
drwxr-xr-x 1 vagrant vagrant 476 Apr 8 2017 20170408024838
drwxr-xr-x 1 vagrant vagrant 68 Apr 8 2017 20170408024828