How I Built This Blog

published 2026-Mar-03 22:37:20
last edited on 2026-Mar-06 03:28:23

When I expressed interest in creating my own blog, my friend told me about the command line tool Pandoc since she knows I like writing in Markdown. Pandoc allows you to simply convert from one markup format to another, and a common use case is to generate HTML from markup files. She also informed me that it is quite simple to host a static web site with plain HTML using one of the built-in gitlab templates. And then after seeing this video I decided to make my tooling with bash scripts.

My text messages where I first learned about Pandoc are dated February 17 and I made a stable version of the blog that I was happy to share to my friends on March 1. While I have tweaked the blog a little since then, I am comfortable in saying that it took me 12 days to get the blog up and running.

Using a custom domain

First I bought the domain I wanted using Porkbun, a site recommened to me by my sister. Setting up a custom domain with gitlab was simple but a bit fiddly. To add subdomains of your purchased domain, you will need to add A and AAAA DNS records with verify specific Answers/Values; see the following image.

Three screenshots showing how to access your domain management page from the Porkbun homepage and what the DNS records should look like for your all of your subdomains.

You will notice there were also some TXT records. The TXT records are added so that gitlab can verify your domain. Using the project sidebar to access the Pages page and then selecting “Domains & settings” (or by directly adding pages#domains-settings to your project home URL). On this page select the “Add domain” button. Make sure “Automatic certificate management with Let’s Encrypt” is selected and add the domain. Then you will need to copy the text under “Verification status” into a TXT record for that subdomain and then press the button next to the “Verfication status” text. Once this is all done press “Save changes”. See the following images:

Screenshots of the instructions shown previously showing how to verify your subdomain to gitlab.

After about an hour Gitlab should automatically manage your certificates and allow your blog to be accessed by your custom domains with HTTPS. In the meantime you can access them with HTTP.

Bumby

I called the framework I used to make this project “Bumby.” The framework has an opinionated directory structure:

content/
# contains markdown files that are converted into blog posts,
# the home page, about page, etc. As well as the css that 
# styles them and images, videos, etc that any individual page
# may show.

public/
# the static files that gitlab serves as the web site.

scripts/
# A collection of scripts automate boilerplate involved in
# creating and maintaining blog posts, as well as building
# the project.

templates/
# contains Pandoc templates used for this project.
# See https://pandoc.org/MANUAL.html#templates

.gitignore

.gitlab-ci.yml
# Configures gitlab CI/CD.

bumby.sh
# A convenience script for running things from the 
# scripts/ directory

README.md

In a linux environment all script actions are performed by executing the following in the project root:

./bumby.sh [action name] [COMMAND LINE ARGUMENTS, IF NECESSARY]

For example, if I want to create a new blog post about my favorite anime I would write

./bumby.sh new why-kill-la-kill-is-the-greatest-thing-ever

This creates a new directory in content/posts directory:

Doing this by hand became tedious and brittle, so I made a script that handled it for me.

Every blog post is stored in a directory with a name like XXXXXX-blog-title. This was so that the order of blog posts was determined by the order of the files when they are globbed. The files in a glob are ordered lexicographically meaning that 2-blog-title would come after 147-blog-title, hence the six-character number prefix for each directory in my framework. (This has the unfortunate consequence that the framework will cease functionality if a million blog posts are made. Might make for a fun challenge.)

The title used in the directory name and markdown file must be dasherized and only contain numbers, letters, underscores, and dashes. This was to simplify the code I had to write. Furthermore, the markdown file in the directory must be the title that comes after the numeric prefix in the directory name. If I changed why-kill-la-kill-is-the-greatest-thing-ever.md to why-i-love-kill-la-kill.md then the build script would not function. Hence I introduced a helper for editing pre-existing blog posts. For example, I could do

./bumby.sh edit why-kill-la-kill-is-the-greatest-thing-ever \   
  why-i-love-kill-la-kill

This would change both the directory name and markdown file simultaneously.

The name of the markdown file is also the url associated with the post. For example, the post shown in this example would be located at https://bumbyskitchen.clodsire.social/post/why-kill-la-kill-is-the-greatest-thing-ever.

Let us view the content of why-kill-la-kill-is-the-greatest-thing-ever.md.

The markdown document simply contains the text “title: Why Kill La kill Is The Greatest Thing Ever” surrounding by line breaks represented by three hyphens.

To understand how this markdown document is handled, let us build the project by running

./bumby.sh build

This creates the following in a directory called dev in the project root:

A screenshot of the result of building the project.

We can open why-kill-la-kill-is-the-greatest-thing-ever/index.html in any web browser to see how the blog looks so far:

Unfortunately the “last edited” behavior was bugged at the time I wrote this blog post.

Evidently the text after title: in the markdown document determines the title shown in the web page. Also notice that it determines what is shown in the browser tab. While, by default, it is a space-separated and capitalized version of the name of the markdown file, you are allowed to change this title to whatever you wish.

In addition to the title you should also provide a summary:

The markdown file shown previously, but now containing the additional text ‘summary: Scattered thoughts on my love for the anime “Kill la Kill”.’

This summary is displayed by any RSS reader which is tracking the blog. With all of this setup we can begin writing the blog content:

A side-by-side comparison of markdown text and the resulting web page.

For more immediacy, I implemented a watch mode that will automatically rebuild the project when changes to the content or template directories are detected. This is done with the --watch option:

./bumby.sh build --watch

When writing new blog posts I build the development version of the blog in watch mode exclusively.

The essentially demonstrates the workflow that I have established for myself with Bumby. The only things of significance I did not show is that you can write mathematics with LaTeX code and this show up in the blog post in the ways you would expect if you have used LaTeX before, and how the build script is used in .gitlab-ci.yml to generate the files in public.

More development details

Why bash

After finishing the project I came to the conclusion that I would not have used bash if I could do it all over again. I used Bash simply because the video I saw which used Pandoc to create web pages used the fish shell script. Their code was very simple so I assumed that my code would also be simple.

It ended up not being simple. At the time I write this sentence I have nearly 1200 lines of shell scripting in my project.

A screenshot of a shell command that reveals I had 1,197 lines of bash scripts in my project.

I can say from experience that Bash does not scale well for large projects. Going into detail about why I feel that way is a blog post of its own. That being said I did enjoy my time with Bash. I like dynamically-typed interpreted languages and the pipe syntax is fun to use even when it creates ugly code. Since WSL comes with Windows now bash scripts are mostly portable. I will happily use it again for simpler use cases in the future.

My sister told me that Make would have been a very good choice for this project. She is probably correct. In fact, her annoyance that I made my job harder myself inspired her to write a blog of her own with Make (and sblg)!

However, I like seeing things through. I like writing tools by hand. I like understanding how libraries work and why they were made. I am infinitely more satisfied with the project I wrote as it is, much more so that I would have been had I used some preexisting static blog generator.

Anyway, that’s as much as I feel like writing on how I made this blog. It is late so I will not fix the bug with the “last edited” text until later.