nanoc3 + vlad = awesome web site deployment Mar 11, 2010

I'm almost ready to take the wraps off a new web site I've been working on.  But while I can't yet show you the site, I can show you the cool software I used to develop it and get it online.

This is a static site, meaning it's pretty much just an informational set of pages.  Previously, I'd been using Radiant CMS for such things, and MediaWiki before that.  But both of those solutions (along with WordPress, Drupal, and other CMS-like things) mean having to deploy a whole web application, complete with a database onto your server.  That takes manpower, RAM, and is a pain whenever you migrate to a different server.

You never really need the complexity of a CMS except when the content changes.  So instead of a CMS, how about software that just regenerates all of your HTML files whenever you change something on the site?

Turns out there's a really good piece of software called nanoc that does just that.  Using nanoc, I was able to build the web site I wanted without a hassle, and compile it to static HTML files in under a second.  (There are already pretty good tutorials, including one on nanoc's web site, for using it.)  I do recommend using nanoc version 3.1 or greater, since it has some very major usability improvements.  3.1 is in beta right now, but should be released really soon.

But what about when you want to deploy the site to your web server?  Well, you could just copy the entire contents of the output folder over there.  That would work, but:

  • It gets to be a pain when you do updates (copy it again!  now copy it again!).
  • It can be hard to back out a change (oops, I accidentally deleted a page).

Well, in the Rails world, there are a couple of good tools to do this kind of thing: the venerable Capistrano and the young, awesomely-named Vlad the Deployer.  There are some big differences between these two tools, but essentially, what they both do is:

  • Build a set of folders on your web server called releases and shared.
  • Check out the latest version of your site from your version control repository, under a new timestamped folder in releases.
  • Copy or link any server-specific stuff you've put in shared into the new copy of your site.
  • Run some tests to make sure the new copy is good.
  • Create a symlink (or change the existing one) called current, pointing to the new copy of the site.

So with this setup, all you need to do is point your web server's root for this site at the current location, and your deployment tool will set up new versions of it with no downtime.  Plus, it's easy to roll back to an older version if you need to - just change the symlink back to the older copy.

I chose Vlad the Deployer for this site, partly because I like the name, and partly because it's smaller and less Rails-specific.

Here's how I did it:

Step 1: Install Vlad

If you've already got nanoc installed, you've already got Ruby and RubyGems.  So installing vlad is easy:

[sourcecode language="bash"] sudo gem install vlad [/sourcecode]

If you're not using Subversion as your version control system (I'm using git), then you'll also need to do one of the following:

[sourcecode language="bash"] sudo gem install vlad-git sudo gem install vlad-perforce sudo gem install vlad-hg [/sourcecode]

Step 2: Edit your Rakefile to enable Vlad

nanoc already put a Rakefile at the top of your project folder.  To enable Vlad deployment, just add the following lines to the bottom of that file:

[sourcecode language="ruby"] require 'hoe'

begin require "vlad" Vlad.load :scm => "git" rescue LoadError # do nothing end [/sourcecode]

(If you're not using git, change "git" to the name of the version control system you're using.  Vlad supports "subversion", "hg", and "perforce" as well.)

Step 3: Write a config/deploy.rb file

Create a folder called config in your project folder.  In there, you'll need a file called "deploy.rb".  A basic Vlad deployment script is as simple as this:

[sourcecode language="ruby"] set :application, "my_web_site" set :domain, "" set :deploy_to, "/srv/my_web_site" set :repository, "git://" [/sourcecode]

(If you want to run the deployment as a different user besides root, just change that on the "domain" line.)

In our case, we need to do a little bit extra.  First of all, we need to override Vlad's default "update_symlinks" task so that it doesn't try to link in some Rails-specific folders from shared.  We can do that like this:

[sourcecode language="ruby"] namespace :vlad do # clear out everything currently in update_symlinks Rake.clear_tasks('vlad:update_symlinks')

task :update_symlinks do # nothing end end [/sourcecode]

The Rake.clear_tasks line deletes the "vlad:update_symlinks" task.  We then redefine it (so that other tasks that try to run it won't fail), but our new version does nothing.

Finally, we need to do an extra step: once our site is checked out onto the server, we need to use nanoc to compile it.  To do that, add this inside the "namespace :vlad" block:

[sourcecode language="ruby"] task :update do run "cd #{release_path} && mkdir -p output && nanoc3 compile" end [/sourcecode]

This will add an extra step to the "vlad:update" task.  It goes into our timestamped folder under releases, makes an "output" folder, and runs "nanoc3 compile" (which will compile our nanoc site into the "output" folder).

OK!  The final version of the deploy.rb file looks like this:

[sourcecode language="ruby"] set :application, "my_web_site" set :domain, "" set :deploy_to, "/srv/my_web_site" set :repository, "git://"</pre> <pre>namespace :vlad do # clear out everything currently in update_symlinks Rake.clear_tasks('vlad:update_symlinks')

task :update do run "cd #{release_path} && mkdir -p output && nanoc3 compile" end

task :update_symlinks do # nothing end end [/sourcecode]


Step 4: Run Vlad!

OK, we're all set to run.  In your project folder, run: [sourcecode language="bash"] rake vlad:setup [/sourcecode]


Vlad will SSH into your web server and create all its folders in the location you told it to.  (It will probably ask you for your server password, possibly multiple times.  If you want to avoid this, you can set up SSH public key authentication.)

Now we're ready to deploy the site: [sourcecode language="bash"] rake vlad:update [/sourcecode]


If you go check in the web server, you'll see that your site has been deployed to the folder you chose, under "current/output".

Step 5: Set up your web server

You need to tell your web server where to find the files for your new site.  I'm using nginx as my web server, so here is the configuration for that:

server {
    listen 80;

    location / {
       root /srv/my_web_site/current/output;

Or for Apache, do something like:

[sourcecode language="xml"] <VirtualHost *:80> ServerName ServerAlias DocumentRoot /srv/my_web_site/current/output </VirtualHost> [/sourcecode]

Restart your server, and boom, you're done.


Now to update your site, you just check your changes into version control, and run:

[sourcecode language="bash"] rake vlad:update [/sourcecode]

Vlad will automatically update your server and change over the symlink.  If you want to roll back to the previous version:

[sourcecode language="bash"] rake vlad:rollback [/sourcecode]