Porting my blog with Hugo

Tue Dec 30, 2014

I’ve just ported my Wordpress blog to Github Pages using Hugo.

Why not use Jekyll?

Jekyll is currently the de facto choice for building Github hosted static websites, I choose Hugo (after first trying Jekyll) primarily because, for me, Hugo has an ineffable Goldilocks quality. Post facto rationale:

  • Hugo is much faster than Jekyll.
  • Hugo has a really useful --watch option.
  • With Jekyll you have to install and maintain the Ruby/Rake/Gems ecosystem – Hugo is just a single executable with no dependencies.

Choosing a theme

My objective requirements were:

  1. Phone and tablet friendly.
  2. Minimal customization required (I find HTML/CSS twiddling such a time sink).
  3. Straight-forward and uncluttered appearance.

The hard part is largely subjective: finding a look and feel that you actually like (look and feel is notoriously subtle and personal). After lots of trawling the Web I stumbled on a Hugo port of the Jekyll Lanyon theme – it is really nice and by happy coincidence is the basis for the excellent Hugo tutorial Hosting on GitHub Pages by Spencer Lyon. The example repo is on Github.

My blog’s Github repository can be found here.

Implementation and Deployment

Couldn’t be easier: All you have to do is read and follow the Hosting on GitHub Pages tutorial.

Additional notes

  • Edit URLs in config.yaml and deploy.sh to reflect those of your Github repository.

  • After cloning the example repo you can start from scratch with:

    rm -rf .git
    git init
    git add --all
    git commit -am "Initial commit of pristine https://github.com/spencerlyon2/hugo_gh_blog master."
  • After creating an empty repo on Github push your local repo master to Github with (use your own Git URL though):

    git remote add origin git@github.com:srackham/stuarts-notes.git
    git push -u origin master
  • I got errors trying to set up the gh-pages subtree branch using steps outlined in the Hosting on GitHub Pages tutorial. A much easier solution is given here – just push the public subtree to gh-pages, when you do this for the first time local and remote gh-pages branches are created automatically (i.e. there’s no need to explicitly setup the gh-pages branch, just run the deploy.sh script):

    git subtree push --prefix public origin gh-pages
  • Before running deploy.sh make sure any files you not want in your repository are excluded by your .gitignore file

  • I configured a custom domain name (http://blog.srackham.com/) for my blog’s Github Pages website by adding a CNAME file to the static directory – see the Github documentation for details.

  • There are Hugo instruction and Github instructions explaining how to create a custom 404 (page not found) page.


Rather than change existing CSS files I customize the look of the site with a separate (./static/css/custom.css) file. Don’t forget to add a link tag to the new CSS file in the ./layouts/chrome/head_includes.html template.

I did have to make one change to poole.css from the example repo: For some reason lists were styled to render like paragraphs – fixed by deleting from poole.css:

/* Lists */
ul, ol, dl {
  margin-top: 0;
  padding-left: 0;
  margin-bottom: 1rem;
  list-style-type: none;

Importing posts from WordPress

I used Exitwp to import the exported WordPress posts to Hugo – it worked like a charm and saved me hours of drudgery.

  1. Export all WordPress data to an XML file – see the WordPress support pages for instructions.

  2. Convert to Jekyll format following the Exitwp instructions.

  3. Copy the posts from (in ./build/jekyll/<wordpress-site>/_posts/) to Hugo’s ./content/posts/ directory.

You will probably need to tweak the imported Markdown files:

  • I had to drop the layout parameter from the front matter header because it was set to post (my posts layout is in posts). This can be automated using command-line Perl e.g. this deletes lines containing author, comments, layout and wordpress_id front matter parameters from all Markdown files and renames the original files with a .BAK extension:

    perl -i.BAK -ne "print unless /^(author|comments|layout|wordpress_id): /" *.md
  • Image URLs were pointing back to the WordPress site, to make them local I copied the images to ./satic/images/ and adjusted the links in the Markdown source to /images/<image-file-name>.

Things I’ve learnt

  • If you are deploying to a non-root base URL (e.g. http://srackham.github.io/stuarts-notes/) you will need to add canonifyurls: true to your config.yaml file. If you don’t, the root-relative URLs (for example, in the CSS file links) will not work. For the same reason, you will also have this problem If you run the hugo server command and view the site locally. I no longer have this issue because my base URL is a root URL (http://blog.srackham.com/).

  • I commit the changes outside the public directory separately prior to running deploy.sh, this keeps content and configuration changes separate from the website files and makes tracking content changes easier.

  • Hugo strips HTML comments from templates when building – nice!

  • The hugo server command builds the site with base URL set to the local server root, this means you must make sure you rebuild with the hugo command before deployment.

  • Using Hugo’s server command --watch option in conjunction with the browser make writing and proofing much more dynamic.

  • Static assets (CSS, images, icons) go in ./static/, Hugo copies them to ./public/ when it builds the site (./public/ is a transient website staging directory).

  • Using Hugo, Git and Github Pages makes for a much easier workflow than I had previously.

As a side note, I like the Blog like there’s nobody reading philosopy, but it has it’s limits. There’s a lot more work goes into a readable and useful blog post than just throwing on-the-fly notes over the wall. On the plus side, putting my notes into a blog ensures that I understand them more then six months later.

Todo list

  1. Enable blog comments using Disqus – maybe.

  2. Enable syntax highlighting.

  « Previous: Next: »