Migrating to Hakyll

As previously mentioned if you follow the blog, I have left WordPress for Hakyll. This is the technical followup going through how I went about setting the site up.

Hakyll Setup

So first things first, install Hakyll. Previously I used cabal-dev, but Cabal-Install 1.18 includes the Sandboxed Builds and Isolated Environments work so that is my sandboxing environment now. This post is helpful for folks switching over.

I thought it might be an experience to write everything for the site in Haskell, using Clay as the CSS preprocessor and Fay for JavaScript. I tried Clay, but it’s math operations on values just don’t work and that’s a deal breaker. I was going to try implementing the operators, but decided to just use LESS so I could move forward. I may visit Clay again soon.

I debated what framework to build the site on, if I used one at all. I’ve used Bootstrap before and like it well enough. I’ve heard great things about Foundation as well, but I’m not as familiar with the Ruby environment, so out of the two, I’m biased towards Bootstrap. For the most part they are pretty much the same, especially with the release of Bootstrap 3 whose revamped grid system borrows a lot from Foundations – and is better for it. But besides the big two, I thought about going leaner and different with things like Responsable, Framless, Golden Grid System, or Open DAWS. I mean, my site isn’t going to be a big thing with complicated interactions, so I could do most stuff by hand. Ultimately though, I think what I would build would come out pretty similar to Bootstrap anyway, so coupled with my familiarity with it and the better grid system in version three, I went with Bootstrap.

Because I’m using Bootstrap, I haven’t needed any custom JavaScript yet, but when I do, I think I’ll try Fay.

Write the code

Hakyll is less a static site generator and more a library to write a static site generator, as is usual in Haskell land. Not too hard to cobble something together from other folks’ example code though. Basic file layout for the project is:

.
├── assets
│   ├── js
│   └── less
├── drafts
├── libs
│   ├── bootstrap
│   └── font-awesome
├── pages
├── posts
├── src
└── templates

Most of it is fairly self-explanatory I think. pages/ holds content that doesn’t really have a “published” date or represent some snapshot in time and are generally kept current whereas posts/ holds the stuff that is time sensitive. drafts/ holds posts that I’m preparing to publish, there is a makefile target that links/unlinks them into the posts/ so I can enable/disable them easily. libs/ holds the git submodules of my front-end third-party dependencies. src/ holds the source code for the site generator. If you want to have a deeper look, the source code is on GitLab.

Moving the content

I used Markdown on Save with WordPress and I only had a few posts, so I just manually copied the markup over. Nothing fancy here.

Static Site Tradeoffs

Because I’m using a static site, there are a few things you don’t just get, such as search and comments.

Search can be done client side (lunr.js1), through a third-party (Swiftype2), or through a server side program. Some more discussion on Stack Overflow.

A potential downside to the lunr.js approach is that the entire site index must be loaded into the clients memory. In principle this seems wasteful for every client to expend the energy to construct the entire search index compared to every client sharing one on the server. In practice, probably not a big deal for the scale of this site (extremely small).

I haven’t decided what I want to do about search yet. For now, people can just use DuckDuckGo/Google to search the site, but I’d like to have a built-in option as well. I’ll probably do a lunr.js thing or make a simple server side search daemon.

Comments can also be handled on the client side code and some third-parties provide easy solutions; some standouts being Disqus and IntenseDebate. Honestly though, this site is extremely low traffic and for the one person every five years who would want to comment, I’d prefer they just email me. Less for me to maintain.

Server Setup

I was hosting the old site on DreamHost and I know others have had mixed experiences with them, but their hosting was fine for me, never had problems. While the hosting was fine, it was shared hosting, which is pretty restrictive. I wanted more flexibility for my site, with root access to install whatever I need and dedicated resources so I can plan what I can/can’t run. So I wanted a VPS. I decided to go with Digital Ocean mostly because of what I think is an incredible value. I’m using the smallest plan currently (512MB memory, 20GB disk space, $5/month) as it suits my minimal needs perfectly and is cheap, cheaper than even the old DreamHost account.

Nothing else too interesting on the server setup, just the basics. Debian, lock down ssh (disable root, disable password login, etc.), enable dotdeb repo (for newer nginx), install nginx, configure nginx (I made use of POSIX ACLs for access to /var/www/ and such), moved DNS to Digital Ocean. For some extra security, I setup and configured ConfigServer Security & Firewall (CSF), which was painless. CSF is nice for non-sysadmin folks (like me) who don’t want to spend a bunch of time learning/setting up/maintaining the important, but often impregnible, software for firewalls, intrusion detection, and/or failed login attempts, as it does it all (mostly) automatically.

Wrap up

All and all, pretty painless migration. Playing with Hakyll is a fun way to learn some Haskell.


  1. Example integrating with Jekyll

  2. Example in the search section