Deploying Docpad to Centos with Capistrano

2014/8/2 20:00

Capistrano is a popular means of deploying code. It's a major upgrade from plain ftp'ing of files, as it allows the means to deploy to any number of servers while allowing server commands to be executed before and after each deployment. It also maintains a variable number of previous releases which allows for quick rollbacks in cases where you mistakenly deployed buggy software or network problems prevented a full deployment of the code.

If your Docpad instance is of any size, transmitting all the generated files can get to be a major pain. It can take minutes to fully upload a a site, not counting all of the server manipulation that may be required afterwards.

This guide will assume you are already using some version control to manage your application. I'll be writing for git, but svn, mercurial, or whatever shouldn't take any additional steps. I'm also assuming you're running a BSD (i.e. Mac OS) or Linux system.

The destination system will be Centos, which is common. I think its syntax is universal enough to apply to any Linux distro with minimal changes.

Setup Your Keys!

Deployments will be performed via SSH keys in this tutorial. If that makes you uncomfortable, I recommend you conquer your fear. SSH keys are a good thing to have. This tutorial from Pai Chou is as good as any. Remember to set the permissions on the .ssh directory of the destination server to 0700 for it to work.

Once finished make sure everything's working properly. Run ssh destination-host-name and make sure you can login. If the username of the account you're logging into doesn't match the name of the account on your development machine, you may need the format of ssh dest-user@destination-host-name.

To be clear, these will be keys used by your development machine to log into your deployment destination. Keys to manage logging into your repo from your development machine will need to be set up on your own.

Install Capistrano

On your development machine you'll need to install the capistrano application. This is a ruby gem so installation should be simple. Typically gem install capistrano is all you need to get going. If you run into any issues refer to the manual

Add Capistrano to Your Docpad Site

Still on your development machine, go to the root directory of your development application. Run cap install.

If everything worked you should get a new file called Capfile and a new directory called config.

Capfile is best left alone. Most of the magic happens in the config directory.

Setup Global Server Settings

Open up config/deploy.rb. You'll see a ruby file where most of the lines are commented out. At the top of the file you should see:

set :application, ''
set :repo_url, ''

application is just a unique key for your application. It's value won't impact the deployment process.

repo_url is the url used to access your repository. This should be the same as how your development box accesses the repo. For git you can run cat .git/config | grep url from the base directory of your project. You should see something like:

$ cat .git/config | grep url
    url = ...

Everything following the equal sign should be copied over to :repo_url.

Now set the deployment location on the destination server via the set :deploy_to. This should be a directory on each destination machine. For the reference in this document, I'm going to use /var/www/docpad-site as the destination. Change it to whatever you need. So my final line will look like:

set :deploy_to, '/var/www/docpad-site'

Setup Deployment User

This one is a personal preference on how I like to do deployments, and is an optional step. I set up a dummy "deploy" user account with no password. Logins are only available if using keys. I do this so any of my laptops can deploy code with the same script.

The "deploy" user will belong to a group with that's permitted to modify the destination directory.

First make sure the group exists, which I call webusers.

$ groupadd webusers
$ sudo useradd -g webusers deploy

This group should also have write access on the destination directory on the destination server.

$ chown -R apache.webusers /var/www/docpad-site
$ chmod -R g+w /var/www/docpad-site

Now since your personal ssh key is already sitting on the destination server, you can just add it to the new user. As root:

$ cd /home/deploy
$ mkdir .ssh
$ cp /home/your-regular-username/.ssh/authorized_keys .ssh/.
$ chown -R deploy .ssh
$ chmod 700 .ssh
$ chmod 600 .ssh/authorized_keys

This assumes that authorized_keys is the name of the keys file. Sometimes its authorized_keys2 or similar. Not the biggest hurdle. It also assumes that authorized_keys contains only the keys you want to access the server. That could be a security risk if you have multiple keys, and if that's a concern you can always copy the individual id_rsa.pub or id_dsa.pub from your development machine's .ssh directory.

To test that it's working, run ssh deploy@destination-host-name. You should be able to login without issue.

For each laptop you or your co-developers want to deploy from, add their public key to the deploy user's .ssh/authorized_keys.

Setup the Production Process

Now we get to tell Capistrano where to put the code. In your code the cap install command should have created config/deploy with a couple files config/deploy/production.rb and config/deploy/staging.rb. These files represent different server types, and allow you to tune the deployment process to suit different environments that you may host the code.

This is a personal site, I don't have any staging environments to play with. I'm only going to work in production.rb.

In the file you'll see lines like:

role :app, ...
role :web, ...
role :db,  ...

Capistrano comes prepared to handle an application server, a webserver, and a database server as part of a normal deployment. You can specify unique commands for each role. For instance, if you want to restart the application after code, or run a special migration script against the db.

Neat stuff, but my docpad site only leverages the web role, so I comment out app and db.

The web role should look like: role :web, %w{deploy@destination-host-name}. If you skipped creating a deploy user, this will be whatever username on the destination host winds up responsible for deploying code.

You can comment out the line that begins with server. That will allow for deployments to multiple destinations, outside of the scope of this tutorial.

First Deployment

Hopefully everything was setup properly. Let's test. On the development machine, in the base directory of the Docpad project run

$ cap production deploy

production here refers directly to the settings in config/deploy/production.rb. You should see a mess of server commands on the development machine.

If you log into your destination server and run ll /var/www/docpad-site you should see a structure similar to:

lrwxrwxrwx 1 deploy  webusers   44 Aug  3 12:02 current -> /var/www/docpad-site/releases/20140803160235
drwxr-xr-x 3 deploy  webusers 4096 Aug  3 12:02 releases
drwxr-xr-x 7 deploy  webusers 4096 Aug  3 12:02 repo
-rw-r--r-- 1 deploy  webusers   73 Aug  3 12:02 revisions.log
drwxr-xr-x 2 deploy  webusers 4096 Aug  3 12:02 shared

So what's going on here?

releases

This is a directory that houses a number of site deployments. Default is 5, but this can be changed via the :keep_releases variable in deploy.rb. Each release is in a directory that is named with the timestamp of the release.

current

This is a pointer to the current release in the releases directory. Running a cap production rollback will destroy and recreate this current pointer to look at the previous release.

revisions.log

A file detailing all the releases. Generally it just spits out the branch version that was deployed.

shared

Sometimes you want data to persist between deployments. Stuff like server-specifc database settings that you may not want to put in your repo. This folder can be used for that kind of task, but it's not pertinent to this tutorial.

repo

Consider this an off-limits system folder. A copy of the root repository is maintained. This is actually a big part of the power of a Capistrano deployment process. Capistrano will maintain this repo to perform deployments, performing updates rather than full code pulls. Since most of your code won't change between releases this dramatically reduces the amount of network transfers.

Hooking Up the Webserver

Last main step. I use Apache for my web hosting endeavors, and it needs to know about the new website location. This is the only Docpad-specific part of the tutorial. You want to point to 'out' within the current directory

I setup a vhost to handle configuration:

<VirtualHost *:80>
    DocumentRoot /var/www/docpad-site/current/out
    ServerName www.docpadsite.com
    ServerAlias docpadsite.com
</VirtualHost>

Then restart the server:

$ sudo service httpd restart

And that should do it. Since Capistrano will always create a current pointer to the current release, you won't need to restart the web server after a deployment.

Next Steps

This covers a basic tutorial on how to setup Capistrano for a simple static site generator. So what's next? For me, the 'out' directory produced by Docpad is something I'd like to pull out of the repo. I'd really like the destination server to be able to generate the site. That will take some server mods outside of the scope of this article, though. I may revist if I get enough time in the near future.