We’ve switched to a static, Jekyll generated site. We decided to make the move when our blog database was broken, but there were additional reasons - we can easily add automation later for whatever we might want to automatically add to the blog or RSS feed, but most of all, a statically generated site makes for a more secure blog. Serving a static site reduces the number of attack surfaces inherently presented by running and serving something dynamic.

Jekyll is pretty simple to use. On a CentOS machine, installation was as simple as installing Ruby, and then installing gem packages “jekyll” and “therubyracer.”

Using Jekyll also simplifies the publishing process. We use git to manage our code, so we’re using it constantly. Thanks to git hooks, we can write posts at the command line and publish them with a simple git push. To ensure a single source of truth, we push to a central backup repository, which then pushes to the blog server where the Jekyll build happens.

Here’s what those post-receive git hooks look like.

For the backup repository

# This file is located at /var/lib/gitolite/repositories/blog.git/hooks/post-receive
# Select the directories git will be looking at.
ASSIGN_DIR='--git-dir /var/lib/gitolite/staging/.git --work-tree /var/lib/gitolite/staging'
# Make sure the staging area is clear
rm -rf /var/lib/gitolite/staging >& /dev/null
# Clone the bare repository into a working directory
git clone /var/lib/gitolite/repositories/blog.git /var/lib/gitolite/staging
# Add the deploy server as a remote
git ${ASSIGN_DIR} remote add deploy git@blog.prgmr.com:/var/git/blog.git
# Add the git server's ssh key to an ssh-agent session to make the key available to git, and push to the deploy server
ssh-agent bash -c 'ssh-add /var/lib/gitolite/.ssh/id_rsa; git ${ASSIGN_DIR} push git@blog.prgmr.com:/var/git/blog.git master'
# Clean up
rm -rf /var/lib/gitolite/staging

And for the blog server

# This file is located at /var/git/blog.git/hooks/post-receive
# Clear the staging area in case of a previous failed run
rm -rf /var/git/staging
# Create a working directory
git clone /var/git/blog.git /var/git/staging

# Build the blogs and clear the target area
cd /var/git/staging/operations; /usr/local/rvm/gems/ruby-1.9.3-p547/wrappers/jekyll build && rm -rf /var/www/html/xenophilia && mkdir /var/www/html/xenophilia
mv -f /var/git/staging/operations/_site/* /var/www/html/xenophilia/
ln -s /var/www/blog-archive/xenophilia/* /var/www/html/xenophilia/

cd /var/git/staging/technical; /usr/local/rvm/gems/ruby-1.9.3-p547/wrappers/jekyll build && rm -rf /var/www/html/xenophagia && mkdir /var/www/html/xenophagia
mv -f /var/git/staging/technical/_site/* /var/www/html/xenophagia/
ln -s /var/www/blog-archive/xenophagia/* /var/www/html/xenophagia/

cd /var/git/staging/xen; /usr/local/rvm/gems/ruby-1.9.3-p547/wrappers/jekyll build && rm -rf /var/www/html/xenophobia && mkdir /var/www/html/xenophobia
mv -f /var/git/staging/xen/_site/* /var/www/html/xenophobia/
ln -s /var/www/blog-archive/xenophobia/* /var/www/html/xenophobia/

# Clear staging for next run
rm -rf /var/git/staging

For now, all of the old permanent links on the blog should still be working. We archived them by using wget to mirror the old blogs. (For reference, in case the linked site goes offline, the flags used were –mirror –convert-links –adjust-extension –page-requisites –no-parent)

All of the links to previous articles should be preserved, and a listing of those articles is available here.