News

Deploying static sites and web apps with Capistrano

Take the pain out of deployments with Capistrano, a powerful tool to help automate your release process

Capistrano800

So you’ve written your dynamic web application or HTML site. You now need to get it onto your web server. It’s time to fire up the FTP client to transfer the files over, right? That can take some time – and what happens if a file is wrong and you want to revert to an older version prior to the update? Perhaps you have more than one server to deploy to, or you may need to in the future.

Enter Capistrano, a free open-source tool designed and developed to automate deployment tasks on remote servers via an SSH connection. It comes bundled with a number of tasks that cover the majority of your default requirements, but can easily be extended and enhanced by writing custom tasks that work exactly how you need them to.
Although initially designed to deploy Ruby on Rails applications, Capistrano can be used to transfer and deploy any web files to a remote server. This tutorial will set up a simple project to deploy and explore the various settings and configurations, as well as how to rollback and update an existing deployment.

DOWNLOAD TUTORIAL FILES

Install gem

To begin using Capistrano for our deployments we first need to install the relevant Ruby gem onto our system. We are going to install the core Capistrano gem, which is incredibly easy. Open your terminal or command prompt and enter the following code to do just that.

001 > sudo gem install capistrano

Capify the project

With the gem installed, we now need to start the process of configuring our application and Capistrano. Change directory into the root of your project and enter the command to capify your application. This will create the two files needed to progress: Capfile and config/deploy.rb.

 001 > cd /your/application/root/directory
 002 > capify .

Application name

Open up the config/deploy.rb file in your text editor of choice. Here we need to start setting some values for Capistrano, relating to the application. Firstly, lets set the name of the application. Ideally this should be descriptive of the app itself and as individual as possible to differentiate from any similar configuration files you may have in the future.

001 set :application, “ultimate_bearzling”

Source control repository

We next need to provide Capistrano with the address details for our source code repository. This address must be accessible by both the local machine that will make the deployments, and the remote machine that will receive them. Although it’s completely optional, we’ll also set the scm type to save Capistrano having to guess.

 001 set :repository,  “git@bitbucket.org/<your repository     address >”
 002 set :scm, :git
 003 set :scm_username, “username for git”

Server details

Let’s now look into setting up the remote server. We can specify the base directory path on the server to deploy to. By default, Capistrano will deploy to a different directory using the application name value set earlier on in Step 3. These configuration options allow us to bypass that and have greater control over the target location.

001 t :deploy_to, “/var/www/#{application}”

Which server?

Capistrano has the ability to control deployments to a number of servers, each with different roles; staging, testing and production, for instance. In this example, we’ll use just one server that contains the web application layer, the web server that will run the application we deploy, and database. This address must have SSH access enabled to allow Capistrano to connect.

001 server “your_domain.com”, :app, :web, :db, :primary =>     true

User access

Whenever you access the remote server via SSH, you’ll need to specify a different account name compared to the one used on your local machine. As a result, you can specify a separate configuration value so that Capistrano knows which username to use to make the connection. If you don’t require sudo to run commands on the remote server, turn that option off as well.

001 set :user, “your_remote_account_name”
 002 set :use_sudo, false

Set up deployment

With the initial configuration values made, we can now make a request using Capistrano to the remote server, which will create the necessary directory structure, as either specified in the deploy_to value or the default structure used by the script. Open Terminal and run the following from the command line to perform the request and achieve this.

001 > cap deploy:setup

Check deployment

We now need to run another deployment task against the remote server. This time, to check and validate (to an extent) the directory permissions created, as well as the existence of required dependencies such as git or svn bins. Run the following in your Terminal to achieve this.

001 > cap deploy:check 

Remote cache

By default, with every deployment request a full repository clone is completed. Depending on the size of the code and application, this can cause some serious latency and overheads on the server itself. We can bypass this by using a remote cache, which will read from the local git repository and run a fetch command instead of a clone.

001 set :deploy_via, :remote_cache

Which branch?

By default, Capistrano will pull from the master branch of the repository. We may want to deploy to a staging server or from a particular feature set or branch. As a result, we can specify within the deploy.rb file exactly which branch to checkout during the deployment process, which offers us a greater level of control.
001 set :branch, “master”

Running a deployment

With the code checked into the remote version control repository (in this case a Git repo) we can now run a deployment to the server. With Terminal or your command line interface open, type the default deploy command to start the process. You will see a number of tasks completed during this stage.

001 > cap deploy

Deployment success

Following our deployment, if we log in to the remote server we can now see that the application directory has been filled with releases and also shared directories. Each deployment is added into a time-stamped directory within the releases folder. On top of that, a symbolic link to the latest release called ‘current’ has also been created.

Updated deployment

Make a change to the index.html file or change something within the version-controlled directory. Commit and push the changes to the remote repository and run another deployment from the local machine. Log in to the remote server to make sure that the current directory symlink has been updated to point to the latest release directory.

Roll back

If for any reason the latest deployment contains errors or you wish to revert to the previous version on the remote server, you can do this incredibly easily using the rollback command. This will delete the unwanted release and update the symlink to point to the previous deployment directory. To do this, run the following command on your local machine.

001 > cap deploy:rollback

Using Passenger

If you are deploying an application onto your web server that uses a Passenger mod_rails layer such as Phusion Passenger for Ruby, Python or Node we can ask Capistrano to restart the system for us. The skeleton deploy.rb file has a custom deploy task commented out at the bottom. Uncomment this and it will override the default deploy task.

001 namespace :deploy do
 002   task :start do ; end
 003   task :stop do ; end
 004   task :restart, :roles => :app, :except => { :no_    release => true } do
 005     run “#{try_sudo} touch #{File.join(current_    path,’tmp’,’restart.txt’)}”
 006   end
 007 end

Override tasks

You may be using Capistrano to deploy static content to your server, or perhaps have no need to restart or migrate your server or application. We can easily override the default tasks in the deployment file to stop certain tasks from running automatically. Firstly we need to define a new namespace block and set the value to ‘deploy’.

 001 namespace :deploy do
 002 end

Add tasks

Let’s start with the ‘restart’ task, which is run by default on every deployment request. Add a new task block within the namespace block, setting the task value to ‘restart’. Now add the following code to return a message to the command line to remind yourself that you are not using an application that requires the restart ability in this process.

 001 task :start do
 002   puts “ this is a static deployment, so we are not     running a start command”
 003 end

Repeat as needed

Whenever a deploy task is now requested, the automatic request to perform the restart task will run the custom task and not the built-in one. Repeat the above process and add as many tasks as you wish to override. We are also choosing to override the stop, restart and migrate default tasks.

 001 task :stop do
 002   puts “ this is a static deployment, so we are not     running a stop command”
 003 end
 
 004 task :restart do
 005  puts “ this is a static deployment, so we are not     running a restart command”
 006 end
 
 007 task :migrate do
 008   puts “ this is a static deployment, so we are not     running a migrate command”
 009 end

Older releases

By default, the last five releases are kept on the remote server, although this can be changed by adding the keep_releases variable to the deploy.rb file. In this example we will only keep the last three releases (just to make sure we have something to roll back to if needed). Update the deploy.rb file and save the changes that we’ve made.

001 set :keep_releases, 3

Clean up

Although we have set the variable to keep a limited number of releases, each deployment request adds another release directory to the structure. You can set the deployment task to run an automatic cleanup after each request by adding the following line in to our deploy.rb file, which will run the deploy:cleanup task for you after each deployment.

001 after “deploy:restart”, “deploy:cleanup”

Force cleanup

The ability to run the cleanup task in this manner is incredibly powerful and a big time saver. We can, however, run the task manually and actually implicitly set the total number of releases we wish to keep as an argument passed in to the request. Simply run the following in your Terminal or command line to perform a clean up limited to keep only two releases.

001 > cap deploy:cleanup –s keep_releases=2
×