Deploying Rails web application using Capistrano, Bundler and RVM

Gurzu Engineer

Developers today are moving fast towards docker image based deployments. However, there are still a few of us who like to stick to a more mature workflow because of the nature of the work we do and the reliability we need to provide . For which, we are very careful about the tools we put into practice among our ranks. So, for those of you who fall among those few and are looking to deploy your first Rails application into a Virtual Private Server (VPS), this tutorial is for you.

Deploying your first Rails application can be confusing and may seem like a daunting task if you don’t know what you are getting into. In this article, you will see how to do just that in simple steps using a deployment automation framework - “Capistrano”. You will know just enough to have your first Rails app rolling in a VPS using Capistrano by the end of this tutorial.

What is Capistrano?

  • Capistrano is a framework built in ruby used to automate the deployment process.
  • Capistrano also includes support for assets pipeline and database migration especially for Ruby on Rails.
  • Capistrano uses SSH for deployment.
  • So, you should be able to ssh into the server from the deployment system.
  • Enter following command to test this:

ssh username@servertodeploy.com

Installation

Step 1:

Add following in your Gemfile :\ We are using Rails 4.2.6

gem 'capistrano', '3.5.0'
gem 'capistrano-rails', '~> 1.1.6'
gem 'capistrano-bundler', '~> 1.1.4'
gem 'capistrano-rvm', '~> 0.1.2'

Step 2:\ Enter the following command to install the gems:

bundle install

Step 3:\ At this point the “cap” command will be available. So, let us capify our project by executing following command:

Cap install

After running above command all the necessary file and folder structure for deployment will be generated.\ Output on console will look something like this:

mkdir -p config/deploy\
create config/deploy.rb\
create config/deploy/staging.rb\
create config/deploy/production.rb\
mkdir -p lib/capistrano/tasks\
create Capfile\
Capified

Step 4:\ By default following line are commented, so uncomment following lines in capfile:

require 'capistrano/rvm'
require 'capistrano/bundler'
require 'capistrano/rails/assets'

Configuration:

The configuration variable can be set in two ways:\ Global

/config/deploy.rb

Stage specific

/config/deploy/production.rb\
/config/deploy/staging.rb

We will be doing global configuration in this tutorial.

\# deploy.rb
\# config valid only for current version of Capistrano

lock '3.5.0'

set :application, 'my_app_name'

set :repo_url, 'git@example.com:me/my_repo.git'

\# RVM path selection: :rvm_type
\# :auto (default): just tries to find the correct path. ~/.rvm wins over /usr/local/rvm
\# :system: defines the RVM path to /usr/local/rvm
\# :user: defines the RVM path to ~/.rvm

set :rvm_type, :system

set :rvm_ruby_version, 'ruby-2.3.1'

\# Default branch is :master

ask :branch, ‘master’

\# Default deploy_to directory is /var/www/my_app_name

set :deploy_to, '/var/www/my_app_name'

\# Default value for :scm is :git

set :scm, :git

\# Default value for :format is :airbrussh.

 set :format, :pretty

\# You can configure the Airbrussh format using :format_options.
\# These are the defaults.
\# set :format_options, command_output: true, log_file: 'log/capistrano.log', color: :auto, truncate: :auto

\# Default value for :pty is false

\# set :pty, true

\# Default value for :linked_files is \[ ]

set :linked_files, fetch(:linked_files, \[ ]).push('config/database.yml', 'config/secrets.yml')

\# Default value for linked_dirs is \[ ]

set :linked_dirs, fetch(:linked_dirs, \[ ]).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'public/system')

\# Default value for default_env is { }

\# set :default_env, { path: "/opt/ruby/bin:$PATH" }

\# Default value for keep_releases is 5

set :keep_releases, 5

Now let us precompile our assets locally and upload files to our server. This will not only reduce the load on the production server but also shorten the deployment time making us more efficient.\ Create a new rake task file under /lib/capistrano/tasks/somefilename.rake

\# somefilename.rake
namespace :deploy do
  desc 'Restart application'
  task :restart do
    on roles(:all) do |host|
\# this will restart passenger server
      execute :touch, release_path.join('tmp/restart.txt')
    end
  end
desc 'Precompile assets locally and then rsync to web servers'
  task :custom_compile_assets do
\# The command inside this block will run in our local machine
    run_locally do
      execute 'RAILS_ENV=production bundle exec rake assets:precompile'
      execute 'tar -zcvf assets.tar.tgz public/assets/'
      execute 'rm -rf public/assets'
\# This command will copy and transfer the assets.tar.tgz to username@servername.com:#{release_path}/
      execute “scp assets.tar.tgz username@servername.com:#{release_path}/assets.tar.tgz"
      execute 'rm -rf assets.tar.tgz'
    end
    on roles(:all) do |host|
\# this command extracts assets.tar.tgz
      execute "cd #{release_path}; tar zxvf assets.tar.tgz"
      execute "cd #{release_path}; rm -rf assets.tar.tgz"
    end
    invoke 'deploy:restart'
  end
end  

Now, that our capistrano configuration is completed, let us deploy our application to serve by doing cap production deploy.

If your deploy is successful then check “/var/www/my_app_name” then your folder structure would look something as like:

My_app_name

* current -> /var/www/my_app_name/release/<latest revision number>/
* release
* * xxxxxxxxxxxxxx
  * xxxxxxxxxxxxxx
  * xxxxxxxxxxxxxx
* repo
* * <VCS related data>
* revisions.log
* shared
* * <linked_file and linked_dir>

Then you need to configure nginx for pointing the incoming request to the appropriate application in your server.

If your nginx configuration is ok then your rails application should be up and live in production.