Setting Up

12 minute read

In which, I decide to start a blog and suffer the consequences.

I finally decided to start a blog. Decidedly not in the roll-my-own camp, I figured git and markdown should be plenty. No servers, no pipeline to rebuild the site, no node_modules and webpack, no nonsense. All I want is to be able to edit markdown files locally, check them into git, and maybe have unpublished drafts.

GitHub Pages seemed a natural choice with the promise of almost one-click deployment for exactly that. So I created a repo, picked one of the pre-loaded Jekyll themes, and immediately had a website backed by little more than an index.md file – perfect!

Then I tried to do stuff.

First, I wanted a custom domain. I already owned the domain and quickly followed the docs to point it at GitHub. But naturally the SSL certs didn’t propagate immediately so my browser started outright refusing to display the site. The domain “works” but I can’t see anything anymore, in the name of security. Setting a custom domain also causes GitHub to redirect the default hosted URL username.github.io/repo to your custom domain, so I’ve also lost the ability to see the site there too. Already one step forward, two steps back. I messed with it for a bit before eventually finding out that it can theoretically take 24 hours to take effect, so I quit.

a few weekends later

Eventually I came back and decided to at least write a draft. I figured I’d git clone, hack up a draft in VS Code, and just see how it looks on the page. And it was that easy to make a new markdown file and get a test post.

Until I tried to look at it.

See, GitHub very nicely takes your repo full of markdown files and does the work to run Jekyll and build them into a website for you. It even triggers a rebuild automatically when you push new files, and you don’t have to so much as install Jekyll. Great! That’s one boilerplate environment, build script, and automation that I don’t have to write, see, or think about.

Except if I want to also run it locally.

The problem with this “hidden magic” approach is it’s only magic while it’s hidden. Since the environment is completely opaque, as soon as you want to do anything to it you’re in disproportionately deep.

Fortunately, GitHub nicely documented how you can setup Jekyll locally. Unfortunately, before I even get through the “Prerequisites”, I already need to install Jekyll and Ruby. It’s recommended I install Bundler to manage the gem dependencies I’ll now have. And there’s a tip that says I ‘may’ need to install a package manager to prevent weird Ruby errors. Before the “Prerequisites” end, they already refer me to 4+ external documentations and the “Troubleshooting” section. Great.

Being familiar with Python version and package management, I knew better than to dare use whatever outdated Ruby version is the system default on macOS and probably corrupt things forever. Sanity dictates we have a pyenv equivalent to manage multiple Ruby versions and a virtualenv way to isolate and control dependencies. And it sounds like that’s what the docs are suggesting too.

Immediately I’m then confronted with the choice of RVM vs rbenv. After going down the rabbit hole on that for way too long, I ended up going with GitHub’s recommendation of RVM. For which I am rewarded with a semi-suspicious looking website telling me the official installation method is curl | bash 😱

While that sinks in, I will also mention that it automatically adds a ton of $PATH hacking to about every shell config file I’ve ever seen and a few I haven’t. But hey, they support fish shell! Just don’t forget to re-source those configs or none of it will work. And then install Bundler and Jekyll too.

About this time, I realize that part of GitHub’s opaqueness is to not include any of the default Jekyll boilerplate files, so I need to audit that and figure out what files need to be created now. Then it’s time to finally build the site and see my test post.

Noting that all commands need to be prefixed with bundle exec or else it might accidentally use wrong versions, bundle exec jekyll build worked to build the site. And bundle exec jekyll serve promptly crashed with some nonsense about “cannot load such file – webrick”. Some quick Googling later, apparently at some point Ruby stopped including webrick but Jekyll still needs it, so the solution is to manually add the magic incantation gem "webrick", "~> 1.7" to your Gemfile and rebundle with bundle update. Now it works.

I have no idea what webrick is.

Right, now that I can finally look at my test post - which mind you comprises entirely of “test123” up to this point - I see the super-easy GitHub theme is… not being applied at all. In fact no styling is applied and I’m left with a completely stark Times New Roman “test123” and nothing else. Turns out the GitHub instructions didn’t bother mentioning that you need to install GitHub’s github-pages gem as well to get the themes. In fact, they don’t even link to it. Because if they did I could’ve saved the time I spent debugging that gem 'github-pages' isn’t quite correct and gem 'github-pages', group: :jekyll_plugins is the preferred incantation. They do note that I am responsible for periodically updating the github-pages dependency or else it’ll get out of sync with the (undocumented) version they’re using on the GitHub backend. I can’t wait for the day I forget to do that and there’s inexplicable differences between local and prod. Time to rebundle…

Now finally I’ve caught up to the one-click template I started with, but also locally.

I attempt to edit my test post to say something slightly more insightful, like “Hello World”, and find that jekyll serve doesn’t reflect any changes unless you shut down the server and restart it. Some googling later, I find there’s an official jekyll serve --watch to watch for changes, but I need yet-another gem install to use it. Based on the repo not being updated for 3 years this probably isn’t the way. There’s apparently also a jekyll serve --incremental which does work.

However, it doesn’t track template dependencies so if I update say the layout of a page, that doesn’t count. I have to touch the post file itself for it to rebuild. And then I have to refresh the page. Hardly hot-reload.

In trying to get it to hot reload, I discover there’s also a Jekyll LiveReload plugin which would be yet another install, but at some point Jekyll built it in. So jekyll serve --livereload is the answer.

Now that I can edit both the posts and the page layout, I find that very little of the template is actually configurable from the config. As usual, if you want to do almost anything, the recommendation quickly devolves into duplicating the raw template file and editing it yourself. Pretty soon, I have to halfway-maintain my own forked theme.

I move on to trying to write a post in VS Code, which I know to have support for Markdown and generally great plugins all around. So I open the Extensions pane and search for “jekyll”. There’s a frequently-installed ‘Jekyll Syntax Support’ right at the top … and it’s deprecated. And hasn’t been updated for 4 years.

They loosely refer me to another extension called ‘Liquid Language Support’ which, as is often the case with ‘replacement’ projects, seems a bit half-baked (it seems to not even have HTML syntax highlighting?) and is already itself out of active development, having not been updated for 2 years. I think I ended up with this plugin but I honestly can’t remember.

Editor’s Note: in writing this, I also realized that VS Code doesn’t have spell check by default. Comically, the extension from Microsoft proper is deprecated and archived. They referred me to another plugin which seems to work (as judged by the relative lack of typos now)

I also finally realized that Jekyll’s templating syntax is not Jinja as I had blindly guessed, but in fact Liquid (so that’s why the extension is called ‘Liquid Language Support’). Which, turns out, is built by Shopify.

Anyways, giving up hope for a decent plugin and resolving to just hand-edit Markdown, I then make my next mistake. I test out creating a second post.

The GitHub “Minimal” theme I had been using up to this point, while looking very blog-like, does not actually have a generated index page that lists all the posts! I suppose I could make one and mess around with this ‘Liquid’ language, but this was supposed to be hands-off and I don’t want to. Instead, I start migrating themes to the “Minimal Mistakes” theme. It seems way more configurable and definitely has blog pages. And even a bunch of stuff I don’t need yet like Tags, Categories, and Search pages, and this fancy “12 minutes to read” thing. And not insignificantly, 100% compatibility with GitHub Pages - says so right at the top. (ominous foreshadowing)

So I rip out all the ‘Minimal’ theme files which I’d now duplicated and modified, and began replacing them with the way that ‘Minimal Mistakes’ does things. One of the main nuisances is, while the theme is quite configurable and almost everything is done from the _config file, that _config file doesn’t hot reload so now most changes don’t either. Oh well.

Another migration nuisance is that my unpublished drafts are no longer unpublished. The ‘Minimal’ theme used the Jekyll concept of “front matter” (marketing-speak for putting random YAML at the top of the file) to let me say published: false on the top of a post. ‘Minimal Mistakes’ however doesn’t respect this flag and doesn’t bother to document what it does respect. Far too much googling later, I find that Jekyll has a native concept of a _drafts/ folder, and anything in there it won’t publish. Fine. Except, they don’t show up locally either which makes it quite hard to write new posts. Upgrading the incantations again, we’re now up to bundle exec jekyll serve --livereload --drafts. One more for bingo.

Around this time, with everything at least seeming to not be completely broken, I made the bold move of trying push to GitHub to see what it looked live. Result: the page still didn’t load due to the TLS cert issues which I guess didn’t resolve themselves. The utter refusal to load anything prevented me from seeing that it also didn’t like my new non-standard supposedly-compatible theme. The build failure that sent an email notification to my phone, however, made that short lived. So now I have two problems. And I guess my blog can page me. You know, just in case the build system that I can’t see and don’t manage ever chucks an error.

I flipped a coin and dove back into the custom domain settings to try and get HTTPS working. It claims that HTTPS won’t work because www is listed as an A record not a CNAME record in my DNS settings. Which would almost be a helpful error message if only it was true. I didn’t and never had any www records set. Regardless, I performed the multi-device login ceremony for my DNS provider to double check all the settings, which were in fact correct. Some sanity checks with dig and propagation checks with dnschecker.org later revealed the same.

GitHub actually has a rather nice DNS checking tool in the settings that will refresh and see if your settings are now right. While it was thinking on that, I went back to the theme issues.

Turns out that reading a little closer, ‘Minimal Mistakes’ is 100% GitHub Pages compatible *when used as a remote theme. Some poking around through the various docs reveals a couple different ideas on how to install it. A few failed pushes and more build failures ultimately resulted in another gem "jekyll-include-cache", group: :jekyll_plugins incantation and a minor config change or three.

I also opted to pin the version of the theme to a specific version. Otherwise, if whoever controls this theme ever updates it, the changes they make will butterfly-effect themselves onto my site. Most likely without me noticing. Worse, it would happen only upon a build of my site, which could be an indeterminate amount of time after the theme changes. So one day, I’ll get around to editing something or maybe even writing a post, and a commit that looks for all the world like I’m adding a new post, will actually brick my whole theme. Or not. I’d have to go be a ‘Minimal Mistakes’ release historian to check for sure otherwise every push is a crapshoot. Not because I changed something, but because the world changed around me. Of course, now I’ll probably forget to update the theme and miss out on something useful.

In between messing with that, I mess around with the DNS checker more. After reading more documentation and making sure that I’d correctly configured the “apex” domain without the “www subdomain variant”, which I had, I ended up just removing the custom domain and adding it back. The DNS checker is thinking…

Finally, things are working locally again. Despite looking exactly the same, the theory is now it will also work on GitHub because it’s a “remote” theme this time. I try and push and somehow there’s a freaking merge conflict. My master branch (or main as the kids say) is somehow out of date on a project that only I have access to. Or… me and GitHub that is. Turns out removing and re-adding the domain caused GitHub to remove and re-add a CNAME file to the repo, which it did in two commits. Mind you there was no net effect of doing that in this case but now my branch is outdated, which was unexpected. Anyways, pull then push and now GitHub is happy with the build too. Unlike my TLS certificate.

Randomly, I just decided to go to the site anyway - and it loaded! Not only that but the TLS cert is valid and with the right domain. I go back to the GitHub settings and they’re magically all green now. I guess turn it off and on again was the answer.

One-click hands-off my ass. But hey, at least I didn’t have to configure Apache.

So, I guess we’re live.

Updated: