Services Spotlight:

How-To Deploy Rails Applications Using Capistrano 3.1 and Windows 7

Written By Corlew Solutions
Updated October 3, 2014
Published March 7, 2014
Why Corlew Solutions?

We write great software and provide amazing technical support. Contact us today if you need help with a software project:

  • Website: Send an inquiry
  • Email:
  • Phone: (703) 688-3058

Article Technology Info

This article discusses the following technologies:

  • Capistrano 3.1 - Capistrano is a Ruby gem that automates deployment tasks.
    (website | github | docs | wiki)
  • Ruby - A dynamic, reflective, object-oriented programming language.
    (website | download | docs)
  • Ruby on Rails - An open source web application framework written in Ruby.
    (website | docs)

Capistrano is a Ruby Gem that helps automate the deployment process for web applications. Capistrano 3 introduces a number of new features and a total redesign. If you have been holding off upgrading to from Capistrano 2, the tool has stabilized and many gems have added Capistrano 3 support. This guide will help users who develop on Windows 7 machines get Capistrano 3.1 up and running and, for most part, the process works very well. There are only a couple Windows specific issues and we’ll point those out along the way.

It took us almost two full days to get SSH and Capistrano 3.1 working correctly, but easily half that time was spent trying to deal with Windows issues. It is our hope that this guide will help get you from A to Z in under an hour. If you see any issues or run into problems, please let us know so we can make this guide as comprehensive as possible. Let’s get started!

Upgrading from Capistrano 2 to Capistrano 3

At the bottom of the Capistrano 3 release announcement page, the author mentions there is no direct upgrade path between the two versions. This essentially means we’ll be deleting all Capistrano 2 related files, clearing the server and starting over.

Step 1 - Create Backups

If you’re starting fresh (i.e. you aren’t using Capistrano 2 in your application), then you can skip this step. We will be deleting everything everything associated with Capistrano 2 from the Rails application and we will be deleting all files in your application folder on the server.

Backup Old Capistrano Files in the Rails App

Copy your deploy.rb, Capfile and any other files (like task files) that you are currently using to a folder somewhere in case you need to reference them later on.

Backup Server Files

You’ll want to copy anything you want to keep around that is not part of your Git repo and put it in a folder outside of the application directory (because we’re going to delete everything inside of it) or download it to your hard drive. This includes things like log files or user generated content that may reside in a public/uploads folder. You’ll also want to copy your secret files like the database.yml or any other config file that is not part of Git.

It’s not necessary to do this right now as we won’t be changing the server until the end of the guide (there’s no sense in bringing down the server while you learn a new deployment process).

Step 2 - Modify the Gemfile

Remove Old Capistrano Gems

If you are currently using Capistrano 2, remove all of the Capistrano related Gems from your Gemfile. They’ve been put out to pasture.

Add New Gems

For a Rails app, the following gems need to be installed in the development group.

1
2
3
4
group :development do
  gem "capistrano"
  gem "capistrano-rails"
end

The capistrano gem isn’t technically required since it is a dependency of the capistrano-rails gem, but it can be added if you need/want more control of the exact version of Capistrano. The capistrano-rails gem enhances Capistrano and tells it how to precompile assets and migrate the database. It also pulls in the capistrano-bundler gem which adds bundler specific tasks.

If rvm, rbenv or chruby are being used on the server then additional gems will need to be installed in the development group. These gems add extra Capistrano tasks and enhance the deployment process to account for using these tools. Add the gems that are relevant to your server setup:

1
2
3
4
5
group :development do
  gem "capistrano-rvm"
  gem "capistrano-rbenv"
  gem "capistrano-chruby"
end

A final Gemfile might look like the following:

1
2
3
4
5
group :development do
  gem "capistrano", '~> 3.2.1'
  gem "capistrano-rails", '~> 1.1.1'
  gem "capistrano-rvm", '~> 0.1.1'
end

Step 3 - Run the Installation Script

Execute the following two commands in a terminal on your development machine:

1
2
cd my_app_root
cap install

This will create files in various places inside of your Rails Application. The main files include:

  • Capfile (in the project root)
  • config/deploy.rb
  • config/deploy/production.rb
  • config/deploy/staging.rb

A new lib/capistrano/tasks directory has been created as well. Any files placed in this directory that end in .cap will automatically be loaded thanks to a line at the end of the Capfile that says:

1
Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }

If you only have a couple small tasks that need to be run each deployment, you may find it easier to add them directly to the deploy.rb file instead of creating a separate .cap file. However, if you have large complex tasks, it may be more useful to take advantage of the .cap file capability. It’s up to you.

Step 4 - Modify the Capfile

The Capfile is nicely commented in Capistrano 3. We need to uncomment some of the line that start with require. In Capistrano 2, many people included these require lines in their deploy.rb file. The new standard is to add these lines to the Capfile.

Since we’re using RVM on our server, we exposed the following require lines:

1
2
3
4
require 'capistrano/rvm'
# require 'capistrano/rbenv'
# require 'capistrano/chruby'
require 'capistrano/rails'

If you need more fine grain control, you can remove the require ‘capistrano/rails’ line and require the components individually:

1
2
3
4
5
6
require 'capistrano/rvm'
# require 'capistrano/rbenv'
# require 'capistrano/chruby'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'

Step 5 - Bundle

Let’s make sure everything loads properly by running the following code in the terminal:

1
2
3
cd my_app_root
rm Gemfile.lock
bundle

Step 6 - Source Control Concerns

This article assumes an external source control host is being used to provide version control for your application. We use both Bitbucket and Github, but there are many other hosting providers available. Before proceeding, you will need to have a repository available somewhere Capistrano can access.

Removing Secrets

It’s considered good practice to keep secret information like passwords, API Keys, etc… out of source control. It’s not as critical in a private repository, but your hosting provider (and any hacker that compromises your hosting provider) will be able to see the information. Also, there may come a time in the future when you need to let an outsider look at a repository (like a new potential client who wants to see some code samples). It’s best to get in the habit of keeping secret information out of the repository, despite the inconvenience. Capistrano makes it easy to manage these files between deployments on your production/staging servers, but you will have to manually share these files between your development machines.

If you have a repository that has secret information, Github has an excellent article that will help you remove the information.

Step 7 - Configure SSH

Capistrano 3 really wants us to use SSH for communication and authentication. In particular, it wants to use SSH when we push code changes from our development machine to our hosted repository; it wants to use SSH when we talk to the various servers that make up our application and Capistrano wants to tell our servers to use SSH when they access our hosted repository to pull down code.

It is possible to use regular old passwords and https access, but Capistrano makes it difficult in some places so we will focus on SSH going forward.

Install & Configure SSH

Please consult our article on setting up SSH on Windows 7. This guide will walk through the details of getting SSH to work on Windows.

Add Public Keys to Repository Hosting Service

If you haven’t done so already, you will need to install your public key on the hosting service you are using for your repository. GitHub, BitBucket have excellent articles on how to do this for their services. Other hosts should have documentation as well.

Testing External Repository Connection

Once your public key has been successfully installed you should be able to make a test connection to the service. For GitHub the command is:

1
ssh -T git@github.com

You might get the following output:

1
2
3
The authenticity of host 'github.com (192.30.252.128)' can't be established.
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting (yes/no)?

Answer yes and continue. You should now see the following:

1
2
Hi user! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.

You can also try a similiar command with Bitbucket:

1
ssh -T git@bitbucket.org

If the connection is successful, carry on. If you are not able to connect you will need to sort this out first. If you can’t connect, neither can Capistrano.

Step 8 - Push To git Via SSH

Check Git Config For Your Application

The next step is to make sure the git config file for your application is setup to authenticate via SSH (as opposed to HTTPS).

1
2
3
4
cd my_app_root
git config remote.origin.url
# You should get output that looks like
# git@bitbucket.org:username/app-name.git

If you get something that says https, then your'e trying to connect via https instead of SSH. Login to your repo host and find the SSH path for your repo. Then either open the {app-root-folder}/.git/config file and edit the url line manually, or execute:

1
git config remote.origin.url "git@bitbucket.org:username/app-name.git" # Replace the part in quotes with your specific path

Test Push

Now it’s time to try a test push. Make a change to your Rails application somewhere and execute:

1
2
3
git add -A    # Add all of the changed files.
git commit -m "Testing SSH push to repo"   # Make the commit
git push  #Push via SSH

At this point the push should go through without asking for a password. You may get prompted to add your hosting provider’s server as known host.

Step 9 - Configure deploy.rb

Circling back to Capistrano and our Rails app, it’s time to take a closer look at the deploy.rb file. For the most part, the deploy.rb has sensible defaults for Windows users, but there are couple gotchas.

Overview

The top part of the deploy.rb file sets variables and the bottom part defines custom tasks to be run during a deployment. Variables are set via:

1
set :variable_name, variable_value  # Set's a variable in Capistrano 3

Variables are retrieved with a call to fetch (which is different from Capistrano 2 which gave direct access to the variable once it had been set).

1
fetch(:variable_name)  # Returns the value of a variable in Capistrano 3

You are not restricted to the pre-defined variables. You could for instance create a new variable called :app_url and store the public url to your application if you needed it.

:application Variable

This can be anything you want and it is mostly used for display purposes. We tend to use the URL of the application so the URL doesn’t have to hard coded in other places.

1
set :application, "my.app.com"

:bundle_flags Variable

This is an option that the capistrano-bundler gem uses. Bundler has a command line option called –deployment, which Capistrano uses by default. Instead of installing your gems in a common location for all apps, it localizes your gems and installs them inside the vendor directory of your Rails app. This is wonderful as it speeds up loading and isolates your application’s gems from other environments. It’s similar in concept to the RVM’s Gemsets. Unfortunately, it leads to a nasty problem for Windows users.

If you’re developing on Windows, but running the production app on Linux, you have probably run into the situation where you need some gems for Linux, but not for Windows. The primary example tends to be therubyracer gem which allows JavaScript code to be executed in a Ruby app. This gem (or an alternative) is needed on Linux, but Windows already has a JavaScript runtime installed (JScript) which Ruby will happily use, so the therubyracer isn’t needed on Windows. If fact, if you try and bundle it on Windows you will get an error.

To get around this error, most people try and configure their Gemfile to conditionally load the gem depending on the platform, but this leads to problems with the Gemfile.lock being different for Windows users and Linux users. You can read more here.

By default, Capistrano uses the –deployment flag when bundling and this exposes the bug. If someone knows of a good way around this, please let us know and we’ll update the article. For now, the most simple workaround appears to be to turn off using the –deployment flag. This can be accomplished by the following setting:

1
set :bundle_flags, '--quiet'   # '--deployment --quiet' is the default

If you’re developing on Linux or the Mac and deploying to Linux, you can probably leave the default.

:deploy_to Variable

This should simply be the full path to where your application lives on the server. The default assumes /var/www/my_app, but you will need to change this if you install to a different location. We tend to deploy to /srv/www so our setting looks like:

1
set :deploy_to, "/srv/www/#{fetch(:application)}

:repo_url Variable

We would like to be able to tell you that this is the place where you should specify the SSH path to your repository on your hosting provider. In theory, something like the following should work:

1
set :repo_url, 'git@bitbucket.org:user_name/app-name.git'

Capistrano is supposed to connect to your server via SSH, and then the server is supposed to connect to the hosting provider via SSH to get the application code. Instead of the server having it’s own SSH credentials, a technique called Agent Forwarding is supposed to use the private key on your development machine and forward that information to the server. We get the following error when we try and use SSH for the repo_url:

1
2
3
4
5
6
Error reading response length from authentication socket.
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

We have more information on how we have setup Agent Forwarding below. If someone figures out a solution, let us know and we’ll update the article. Until this gets resolved, we have been forced to use https authentication.

1
set :repo_url, "https://user_name@bitbucket.org/user_name/app-name.git"

If the password to your hosting provider does not use any symbols (at least not the ‘@’ symbol we think), then you can actually embed the password in the path as well which stops Capistrano from asking you for it. Before we show how that’s done, we need to backup.

It would be nice if the deploy.rb file was in the repository. It, however, would not be nice if your GitHub or BitBucket account password was added to deploy.rb and then got stored in the repository. Therefore, we recommend creating a new file inside your config directory and using that to store the password. This file will obviously not be added to the repo. Let’s call this file secrets.yml. The contents are stored in YAML format:

1
repo_pwd: my_pass_here

With this file available, we can modify our deploy.rb to read the password from it. Place the following code at the top of deploy.rb.

1
2
config=YAML.load_file('config/secrets.yml')
set :repo_pwd, config["repo_pwd"]

Now that we have our repo password in a variable, we can dynamically add it to our HTTPS path:

1
set :repo_url, "https://user_name:#{fetch(:repo_pwd)}@bitbucket.org/user_name/app-name.git"

:linked_files Variable

Some files should be shared between releases. For instance, we would like our log files to stick around each time we deploy as well as any files users may upload while using our application. The :linked_files variable allows us to target specific files that are release independent. It’s the perfect place to tell Capistrano to share our database.yml file. (In this case, the secrets.yml file does not be to be added because it does not need to exist on the production server. If you add more data that is used in other places in your application, you can add it to :linked_files and treat it the same way as the database.yml file.

1
set :linked_files, %w{config/database.yml}

If you were previously tracking the database.yml file inside your repository, you should remove it from git and add it to the .gitignore file by executing:

1
2
git rm --cached config/database.yml
echo  config/database.yml >> .gitignore

This will take the file out of the next commit, but leave the file in your actual directory. Note, this only removes the file from the next commit and future commits. Older commits will still have the information. Consult this GitHub article for fully removing sensitive data).

Later on, we have to manually upload those two files to the server so Capistrano can find them.

:linked_dirs Variable

Like the :linked_flles variable, this lets Capistrano manage entire folders that should be shared between releases. Many applications store user uploaded files in an uploads folder. We would tell Capistrano to manage this folder by specifying:

1
set :linked_dirs, %w{public/uploads}

Step 10 - Update the production.rb and staging.rb Files

Capistrano 3 lets us specify settings based on the type of server we are trying to deploy to. We’ll focus on the production.rb file, but the changes would be similar for the staging.rb file. For a basic application you might have something like this at the top:

1
2
3
role :app, %w{user_name@server.com}
role :web, %w{user_name@server.com}
role :db,  %w{user_name@server.com}

Depending on how your application is setup, you may have the database, application and web servers on different machines. For a Ruby On Rails application that uses Passenger and Nginx, the app and web server are typically together on the same machine. If you need to define extra roles, you can do so as well here.

Below the roles definition area, you can add more detailed information about the server.

1
server 'server.com', user: 'user_name', roles: %w{web app db}, ssh_options: {keys: %w{~/.ssh/id_rsa}, forward_agent: true, auth_methods: %w(publickey)}

Go ahead and adjust this file for something that makes sense for you application.

Step 11 - Sanity Check

Now that Capistrano is configured, let’s try to connect to Git via Capistrano and see what happens. If you’re deploying to a production server you would run:

1
cap production git:check

If you’re deploying to a staging server you would run:

1
cap staging git:check

If the git check finishes successfully, then you can continue on. If you get some errors you should untangle that first.

Step 12 - First Deployment with Capistrano 3

Prepare the Server

If you have an existing application on your server, you should now backup any files that are not under source control and move them to your hard drive suing SFTP (or FTP) or move them to a folder outside of your application on the server. In particular, you’ll want to grab any log files, user generated content or files that contain secrets (if they’re not already on your hard drive).

If you do not have an existing application, you should create a folder for it on the server now. (The full path to the application on the server, should be set in the :deploy_to variable in your deploy.rb as well.)

1
2
3
ssh user_name@server.com
sudo mkdir /srv/www/my-app.com   # /var/www may be a better location for your server
sudo chown user_name:user_name /srv/www/my-app.com   # Make sure the deploy user owns the folder

Clear the Directory

If you have an existing application we need to delete everything in the root application (you could keep non source code files in there if you wanted). We need to start fresh.

1
2
3
4
5
ssh user_name@server.com
cd my_app_directory
rm -rf *   # Kiss your files good-bye
ls -lha    # Verify the directory is empty
exit

Create the database

If you have an existing application, then the database should be left alone.

If this is the first time you are installing the application, you should use your preferred to create the database and database user that can access the database. This should correspond to the data in the database.yml file. Capistrano will try and run the migrations as part of the deploy and it needs a database to act on.

Run the Deployment

At long last we are finally ready to deploy. If you’re coming from Capistrano 2, the old command was simply cap deploy:migrations. In Capistrano 3, we must specify the type of server we want to deploy to (and the migrations will automatically be run). If you are still connected to your server via ssh, disconnect now.

To deploy to the production server, execute:

1
cap production deploy

To deploy to the staging server, execute:

1
cap staging deploy

Almost immediately, Capistrano will ask you for your ssh passphrase. This will happen every time so go ahead and enter it now. Capistrano will execute a couple commands and eventually break. You should see an error like the following:

1
ERROR linked file /srv/www/app.com/shared/config/database.yml does not exist on app.com

As expected, Capistrano has been told to link your database.yml file, but it can’t find it on the server where it expects. We need to manually upload that file now. If we look at the app directory on our server, it now contains two folders releases and shared. Inside of the shared directory you will find a config directory. You will need to upload your database.yml file into that config directory. Make sure it has the correct file ownership and permissions before leaving.

If you have linked_dirs, you should set them up now at this point as well by copying the folders and files from the backup location to the correct spot in the shared directory on the server.

Once this is done, try and deploy again. If everything goes well, Capistrano will try to clone your app from GitHub and work the rest of it’s magic. You may see a couple lines in the output that say “failed”. This is likely ok as long as the deploy finishes. You may be asked for your phassphrase again as well.

Wrapping Up

Once the deploy finishes, take a look at your root application directory on the server. It now contains a symlink called current which points to the current release. It contains a releases which holds the last “n” releases and it contains a repo directory.

Step 13 - Restarting the Server Automatically on Deployments

Take a look at the bottom of your deploy.rb file. You should see the following code:

1
2
3
4
5
6
7
8
task :restart do
  on roles(:app), in: :sequence, wait: 1 do
      # Your restart mechanism here, for example:
      # execute :touch, release_path.join('tmp/restart.txt')
  end
end

after :publishing, :restart

Capistrano lets you add additional tasks after it’s own internal tasks using the after and before method. In this case, Capistrano is being told to run the restart task after the publishing task has finished. Out of the box, this task does nothing and depending on your server you can either uncomment the line that starts with execute in the task or implement your own logic. For our Nginx based servers we use.

1
2
3
4
5
task :restart do
  on roles(:app), in: :sequence, wait: 1 do
     execute "sudo /etc/init.d/nginx restart"
  end
end

This task is complete, but it won’t work yet. The problem lies with using the sudo command from within Capistrano.

Step 14 - Enable Passwordless Sudo

Capistrano 3 really does not want us sending passwords across the net (see the bottom of this document for Capistrano’s position on the matter) and they have made it much harder to launch command prompts (and get input) in the deploy process. Instead, they recommend using password-less sudo for any commands that require sudo on the server (like restarting web server). This is easy to setup.

1
2
ssh user_name@server.com
sudo visudo

At the end of the file, append the following line:

1
deploy ALL=NOPASSWD:/etc/init.d/nginx

The above line let’s our deploy user execute the nginx start, stop and restart commands without supplying a password (although he still has to put sudo in front of the command). You need to specify full paths for every command you want to replace deploy with the correct user name.

You can test this is working properly by rebooting the server and then executing sudo /etc/init.d/nginx restart. If everything is working the server will restart without needing a password.

Recap

There were alot of moving parts in this tutorial. At this point you should have the basics of Capistrano deployments working. If you’re using multiple servers, you will need to repeat the setup instructions on all of them to get the full process working; hopefully this article helped point you in the right direction.

We hope you found this article useful. If you see any mistakes, missing features or ways to improve it, please let us know in the comments below so we can update its contents. If you're willing to link to us, we would sincerely appreciate it!

References

Corlew Solutions is a Web Design and Web Application Development company based in Fairfax Virginia, minutes away Washington D.C. If you're looking for great web design from the Northern Virginia area or web design from the Washington D.C. area we can help. Contact Us today!

comments powered by Disqus