Last July, I started thinking seriously about publishing a blog and quickly put together around a dozen posts, with another few dozen fleshed-out ideas. Now, a year and a half later, I have finally flipped the switch. So…what the heck took so long!?

The Goals

I started out with a basic idea of what I wanted the blog to be able to do beyond just showing the pages.

  • Ingest Markdown files so that I can store the original text under version control, separate from everything else. Even if the blog itself crashes and burns, the content should always be easy to move or archive.
  • Allow easy changes to the styling to match my personal website. Consistency is important.
  • Not require any additional software running just to serve up the blog. Previously, I worked with WordPress and Blosxom, and briefly checked out Ghost, but none of them quite seemed worth the trouble of maintaining and patching, here.
  • Ideally, but not necessarily, allow for the occasional chunk of code to run live.
  • Act like a blog, for the most part.
  • Allow for multiple blogs on the same server, potentially, as I spin up new projects.

Because I didn’t really want to run additional software and because running multiple instances would be trivial, most of the requirements led me to the world of Static Site Generators, frameworks that take source content and transform the input into web pages that look like an application. That sounds like it might help make the decision, but there are hundreds of these things, so I needed to pare down the list in some way. While I’d like to say that I came up with a set of critical rules, the reality is that I picked systems that were getting some buzz and tried them out.


My first test was with Hugo and…I probably didn’t give it enough of a chance. The showcase blogs all look very similar, though, and I often have trouble running Go code for some reason, so while I managed to create and build a simple blog, I ended up deleting the project and moving on.


The next system—the system that took up most of my time on this experiment—was Gatsby. There is a lot to like about Gatsby. It uses React in its templates, which I like and helps with modularity. It has a lot of “starter packs” that lay out the site in a reasonable way from the start. The build process optimizes the pages pretty well. And there’s even a layer that allows a page to pull in external data to process it.

By all accounts, Gatsby should have been the winner, but somehow wasn’t.

My first attempt worked surprisingly well up until I added a plugin (a JavaScript package) for some simple feature. That plugin was incompatible with some part of the starter kit, and Gatsby turns out to be fragile in some cases, no longer able to build the site. Worse, upgrading the existing patches and/or removing the plugin failed to fix things. I quickly became frustrated with this and, because I still wasn’t sure I needed the blog, ultimately put everything aside.

Gatsby, Round 2

Fast forward about a year, and I decided that a blog would still be useful and Gatsby deserved a second chance with a more blog-focused starter.

I had to rewrite the “frontmatter” for each post, but I was able to more quickly create the styling I needed, this time, but started running into trouble again, when I wanted to add some metadata to posts. I wasn’t able to get that to work, probably because I’m insufficiently conversant with GraphQL.

On top of that, I also had problems deploying the generated code to my existing website. The links didn’t work in a subdirectory, and there’s no explicit way to set this up that I could quickly find.

But then, Gatsby just…stopped working. Again. I’m still not sure what I did to trigger a change, but I tried a few things to fix the problem that only made things worse.

Could I have taken this problem to Stack Overflow for advice? Probably, and I probably would have tried if this was for an employer, but using Gatsby wasn’t an important part of the blogging. So, I dropped Gatsby and moved on.


Unlike the other systems, Jekyll is more than ten years old and, thanks to its adoption by GitHub as a supported approach to blogging, is widely used and very stable. And unlike Hugo and Gatsby, Jekyll is designed primarily for blogging, rather than intended for any site with blogging being just one option.

Again, I needed to update the post frontmatter to fit Jekyll’s scheme. However, styling the Jekyll blog was surprisingly easy. Adding metadata to posts, like a thumbnail image and a summary, also turns out to be relatively easy.

Even better, Jekyll’s configuration has a baseurl option that sets the blog to operate out of a sub-folder.

So, after all that farting around with sophisticated systems that I thought might be fun, the winning system is one of the first. I probably should’ve just started there. Oh, well…

Modifying Jekyll

Being part of the Ruby ecosystem, the Jekyll themes are stored as global gems (packages). This means that all of the files are held in common. Overriding the common files is handled by making a local copy of the important files and making whatever changes are needed.

To do this, we need to first find the theme’s package. The default theme (found in the _config.yml file) is named minima, so we call…

bundle info minima

…and we get output that looks like…

* minima (2.5.1)
	Summary: A beautiful, minimal theme for Jekyll.
	Path: /var/lib/gems/2.5.0/gems/minima-2.5.1

At the listed path, there are folders named (in my case) assets, _includes, _layouts, and _sass. Creating the relevant folder inside the Jekyll project and copying the relevant file (for example, _layouts/post.html) provides a local file that can be modified with Shopify’s Liquid templating system, making it extremely easy to make significant changes.

Adding Comments

Of course, it’s not a blog unless people can leave comments, ideally comments that can be moderated, since certain people can be…less than thoroughly useful, let’s say.

I initially tried working with Isso, but while it was easy enough to install and passed some basic tests, apparently needs more infrastructure set up than I was willing to investigate, so I set that aside.

Coral was also worth a quick experiment, but takes a lot of administrative work to get it running, unfortunately.

The other major alternative that fits my minor requirements is Hashover, despite the fact that it runs in the filesystem, making it slightly less portable than would be ideal. However, it (or rather, its successor project) worked right out of the box and was trivial to change the styling to match the surrounding blog.

Hashover has a nice administration system. It would be slightly nicer if it used Libravatar instead of Gravatar for user images, but I’m willing to let that pass for now and investigate possibly adding the feature in the future.

The Winners

It’s entirely possible that I didn’t give the other systems a fair enough shake and/or my problems could have been easily fixed with obvious advice and/or the other projects weren’t meant to be run on a VPS with a lot of other projects running. It’s also very likely that I overlooked systems that would have been perfect for my needs and didn’t bother to investigate them. But for my use case and the time I was willing to put into the search, the combination that works for me is:

And that’s what you’re looking at here.

It’s missing some features, of course.

  • I would like to figure out what to do with the post tags, for one. They currently just sit in unused metadata.
  • The blog will eventually probably need a search feature as it grows.
  • I haven’t tested whether Jekyll will automatically paginate, once the number of posts becomes large, so that may become important.
  • As mentioned, I’d like Hashover to use Libravatar instead of Gravatar.
  • I may also want to disable anonymous comments.

I’ll post an update and link to it from here, if I decide on a reasonable way to make any of those work.

Regardless, the good news is that, if something better comes along, the source files for both the blog posts and the comments are stored separately, making it easy to transfer to them to another system.

Credits: Untitled header photograph from PxHere, made available under the CC0 1.0 Universal Public Domain Dedication.