Setting up Jekyll, from the beginning

(Note: This post is originally from 2017, and is copied to this new site for historical reasons. Opinions, network infrastructure, and other things may have changed since this was first written.)

I’ve finally gotten to the point where I need to write down all the solutions to my various ideas and/or problems. Therefore, I’ve finally gotten to a point where I actually need a blog like object.

I wasn’t particularly inclined to write my own blog software, so I went looking for a pre-made solution. I had a few requirements:

  • Must be self-hostable (and therefore open source)
  • Must not cost money (I ain’t got that kind of cash)
  • Must have sane rich text formatting
  • Should be easily exported to some common format, in case I need to migrate to something else later
  • IS NOT WordPress.
  • Supports some sort of organizational system, without being a full blown CMS.

Of the handful of options I found, only one seemed to fit the bill – Jekyll. A few came close: Ghost would have been fantastic if it had a free version, and Medium, obviously, can’t be self-hosted (though I might script an automatic mirror later if Medium has a public API). But Jekyll ticked all the boxes, and has the added benefit of basically just being a “Markdown compiler”, more or less, which means I can integrate it with my existing Git and Saltstack setup – all I have to do on that side is bang together a shell script with a jekyll build command in it. The Jekyll documentation even has some great documentation about how to configure jekyll new to use whatever theme you want.

The problem with that is that method assumes you want to install Jekyll themes using the gem package manager. And I’ve got nothing against that. But all the theme authors seem to prefer you just clone their GitHub repositories instead, and I can’t find support for that in Jekyll configs. So what I actually ended up doing was this:

$ git clone ~/record
$ rm .git && git init
$ git remote add origin ssh://internal-vcs/record.git 
$ vim _config.yml # configure blog title, update deprecated config var name, etc
$ bundle update # something to do with ruby's package management, as far as I can tell

That should be a good generic set of instructions for any theme you find on GitHub, just replace ~/record with whatever path you intend to manage your Jekyll site from, and ssh://internal-vcs/record.git with whatever your “upstream” Git remote is. Then commit things to your new and initially empty repo, and push, like you always have.

The next thing I needed was some kind of “new post” script, because Jekyll likes to have its files in a certain way and while it’s certainly possible to type the current date and the slug by hand, I’d rather keep my wrists. So I wrote a script,, to do the legwork for me.


# Generate file in _posts subdirectory.
# Running "./ not gonna hide from jekyll" on July 10th would generate
# a file named "_posts/"
POSTDATE="$(date +%Y-%m-%d)"
POSTSLUG="$(echo $* | sed -e "s/ /-/g")

# Jekyll expects a "header" of sorts in YAML with metadata like
# which layout template to generate this page with, what its title
# is, its tags, etc
# Put a barebones one in the new file
echo "---" >> ${POSTPATH}
echo "layout: post" >> ${POSTPATH}
echo "title: SET ME" >> ${POSTPATH}
echo "---" >> ${POSTPATH}

# Open the new file in a plain text editor and get to posting
# Respects $EDITOR if set, otherwise assumes vim

So now Jekyll is basically set up “client side”. The next question is, how do I get it to build server side? For that, I need a Git hook:

git clone ${PWD} /tmp/record.out
cd /tmp/record.out
bundle update # ruby package manager again
jekyll build -s . -d /srv/www/record

My actual hook is more complicated because I’m using Saltstack to distribute my web server data, but that’s a basic version so it’s clear on what exactly this hook needs to accomplish. This hook is attached to the record repo in Gitolite (option and rebuilds the site with Jekyll every time I push commits.

Now what’s left on my todo list is to fix my Saltstack hook so it actually applies changes on commit, instead of me having to run salt \* state.apply manually.

  • October 13, 2022