How to Deploy Sinatra Applications with Capistrano

Sinatra is a popular Ruby minimalist web framework. Capistrano is the most frequently used deployment tool. This article shows you how to use the two together.

Cut your Rails test suite down to a few minutes with one-click automatic parallelization.

Automate parallelizing tests

Introduction

Rails is great, but often it is not the best tool for creating smaller applications. For smaller size apps, especially those that are mainly focused around pure JSON APIs, Sinatra is often a far better option. Unfortunately, the majority of learning resources in the Ruby ecosystem are focused on Rails, and leave out the details for other frameworks. One of the essential web application development processes is application deployment.

This article will try to teach you about Capistrano— a remote server automation tool that lets you execute arbitrarily tasks over SSH. It is very useful for automating your application's deployment and setting up common repetitive tasks for remote machines.

Prerequisites

This article will assume that you are using the following tools to develop and serve your applications:

Installing Capistrano

The first step we need to take is to add Capistrano as our applications dependency. To achieve that we will add the following line to our Gemfile:

gem "capistrano"

Install the above gem by executing bundle install in your shell.

To get started with Capistrano we need to "capify" our Sinatra project. In other words we need to let Capistrano create the configuration files and the file structure that it needs. To do this, run the following command in your application's root directory:

bundle exec cap install

The above will append the following file structure to your application:

├── Capfile
├── config
│   ├── deploy
│   │   ├── production.rb
│   │   └── staging.rb
│   └── deploy.rb
└── lib
    └── capistrano
            └── tasks

With this we are ready to use Capistrano with your Sinatra app.

Installing Addition Dependencies

We will install two addition dependencies for easier deployment management, the capistrano-bundler and the capistrano-passenger gems. These gems will help us to install our Bundler-defined dependencies on the remote server and to start/restart our Phusion Passenger based application.

Let's add them to the Gemfile:

gem "capistrano-bundler"
gem "capistrano-passenger"

Install them by executing bundle install.

At this point we need to inform Capistrano to include those two dependencies. We will achieve this by editing the Capfile in our project's root directory.

The Capfile is the first file that Capistrano loads and it is responsible for loading all the dependencies that your application needs for deployment. By default it includes deployment commands and loads all the tasks from the lib/tasks directory.

Luckily, these gems are so common that the Capfile already includes them, but comments them out by default. Uncomment those two lines, to require the gems. Those lines should look like this:

require "capistrano/bundler"
require "capistrano/passenger"

The next time you execute a Capistrano task, these gems will be available in your Capistrano scripts.

Defining Servers and Roles

By default, Capistrano will create two types of server environments for our application: production and staging. The configuration file for each of those environments can be found in the config/deploy/ directory.

In these files you can define the server you are going to deploy to. For example, we can define a server for our staging environment if we add the following line to the config/deploy/staging.rb file:

server "staging.sinatra-app.com", :user => "deployer", :roles => %{web app}

In the above command we have defined a server that lives under the staging.sinatra-app.com domain. We could have used the IP of the server instead, like in the following example:

server "111.222.333.444", :user => "deployer", :roles => %{web app}

The next thing we want to notice is the user parameter. That option tells Capistrano to use the deployer Unix user on the remote server. Of course this can also be changed to match the user on your specific deployment machine.

In case we have several machines where we want to deploy simultaneously, we can simply repeat the server command to add additional servers:

server "staging1.sinatra-app.com", :user => "deployer", :roles => %{web app}
server "staging2.sinatra-app.com", :user => "deployer", :roles => %{web app}
server "staging3.sinatra-app.com", :user => "deployer", :roles => %{web app}

A common option when defining the servers for the production environment is to hardcode the branch to master, and thus make sure that we only deploy the latest stable build. We can define the branch like this:

server "staging.sinatra-app.com", :user => "deployer", :roles => %{web app}

set :branch, "master"

The last argument that you can see defined in the above examples is the roles option. With it we can limit the tasks that are run on some of the servers. For example, if we keep our database on a separate machine, we can define that server like this:

server "staging.sinatra-app.com", :user => "deployer", :roles => %{web db}

In the above line we specified that on this server we want to execute only the database specific tasks.

Configuring the Deployment

Capistrano's main configuration file is the config/deploy.rb. This is the file where we define the name of our application and a URL to its repository.

Let's say that our application is called test-application and is hosted on this Git server git@github.com/tester/test-application.git. We then need to set the application and repo_url options in our config/deploy.rb file:

set :application, "test-application"
set :repo_url, "git@github.com/tester/test-application.git"

When Capistrano deploys our application, it is actually executing git pull over an SSH connection. That is why we need to provide the URL to our project's repository.

The default deploy path is inside the /var/www directory, but often we want to deploy our applications to the home directory of the remote user. For example, if our user on the remote server is joe we would set this path to be:

set :deploy_to, "/home/joe/test-application"

The above line will tell Capistrano to deploy the project under the test-application directory, in the home of the joe user.

When Capistrano deploys your application, it will create a releases, current and shared directory in the deploy_to path. The current path will be a symlink to the latest release in the releases directory, while the shared directory contains files that are symlinked into every release.

Managing Secret Files

Often, our application depends on external APIs or a database connection. Both of them usually require a secret password for access. Because we should not keep those passwords checked in to our repository, we will use the linked files mechanism provided with Capistrano.

First we need to define a path of our secret file, relative to our project's root directory. For example, we could decide to use config/secrets.yml with the following content:

API_KEY: xyz

With that in place, first we will add that path to our .gitignore file to prevent it from checking in to our repository:

# .gitignore
config/secrets.yml

Secondly, we need to SSH into our server and store the content of the file in the shared directory to the config/secrets.yml path so it will be linked into each release. The full path of our remote secrets file should be test-application/shared/config/secrets.yml if test-application is the name of our application.

The next step is to tell Capistrano that this file is linked into each release with the following option in the config/deploy.rb file:

set :linked_files, ["config/secrets.yml"]

The above line tells Capistrano to include the secret files from the shared directory into the project's config directory on each release.

Setting up SSH Keys

Capistrano needs two SSH key pairs to deploy to your servers.

The first SSH key pair will make sure we are able to enter the remote machine where we want to deploy. It is always a good practice to check your connection before deployment by manually entering the server. For example, if the name of the remote Unix user you are using for deployment is joe we could try to SSH into the remote server with:

ssh joe@1.2.3.4

Where 1.2.3.4 is the IP of the remote server.

The second SSH key pair is concerned with pulling from our git repository. Each time we deploy, Capistrano will pull a fresh copy of our repository into the deploy path on the remote machine. For this to succeed we need to set up a private key on the remote machine that has access to our repository.

Capistrano also offers an alternative way to pull from our repository. It can use our local keys, forward them in our SSH session to the remote server, and use them to when pulling the project. This way we don't need to store our SSH keys on the remote server and tighten our security a little bit.

To achieve this, we need to enable the following option in our config/deploy.rb file:

set :ssh_options, { :forward_agent => true }

Before we deploy, we also need to make sure that our SSH agent is running. To run the agent and put your keys into the agent type the following in your command line:

eval `ssh-agent`
ssh-add ~/.ssh/id_rsa

To test if we have all the necessary keys we could SSH into the remote machine and try to pull from our repository.

igor@localhost ~ $ ssh joe@1.2.3.4

joe@1.2.3.4 ~ $ git pull git@github.com/tester/test-application.git

If everything works without issues, we are ready to deploy.

Deployment

With the above steps in place we can deploy our application with a simple shell command:

bundle exec cap production deploy

That line will do several things on the remote server:

  • It will create the project's directory and the releases, shared and current directories.
  • Install all bundle dependencies with capistrano-bundle.
  • Run/restart Passenger with the capistrano-passenger task.

To deploy to a staging server environment, simply:

bundle exec cap staging deploy

Conclusion

Capistrano is an excellent tool for automating your application deployment. There is of course much more to Capistrano than what we covered in this tutorial. Some great resources are:

C8072c254e533750d092e3a3a513c598
Igor Šarčević

Programming and math are his passion. Developer at Rendered Text, actively working on SemaphoreCI. Turns into a Japan obsessed ninja by night.

on this tutorial so far.
User deleted author {{comment.createdAt}}

Edited on {{comment.updatedAt}}

Cancel

Sign In You must be logged in to comment.