March 30th, 2024
DIY'ing a blog in 2024
I decided to put something up on https://satragno.com on a bit of a whim and the easter holidays seemed like the right time for it.
Hosting the website
I wanted to have full control over my content, so no medium or similar writing platforms. Plus, I work on a browser, I should get some exposure to writing websites every once in a while!
I chose https://www.nearlyfreespeech.net/ to host my site. They have a USD 0.01/day plan plus very cheap pay-as-you-go resources, pretty hard to beat them in terms of price.
Hosting a static website with them is trivial. Create an account, create a site,
point nameservers to their DNS, scp your files in. For TLS, they give you a
script you can run that
sets up Let's Encrypt for you. It could not be any easier.
After quickly whipping up something that looks like a business card, it was time to add a blog.
Generating the content
I'm a fan of lightweight websites: no tracking, and as little dynamic content as needed. That brings costs and complexity down, and rules out solutions like wordpress. I ended up choosing MkDocs which I guess is geared mostly towards documentation, but seemed alright. I ditched the default themes and instead wrote one from scratch. It's very bare-bones but I can update it as I go.
I can write each post as its own markdown file and preview it live on my browser. Deploying it is as easy as running a command and copying the right set of files. Since all the content is just text, I can keep it in a private GitHub repository.
A quick and dirty custom theme
I wanted a homepage that would list all the posts one after the other. Each post would have a header with a permalink to itself, a button to go back, and a list of all previous posts at the bottom. This should work fine for a small number of posts, and I can always tweak it later. This was pretty straightforward except for one small detail. Here's the original version of the code, simplified to showcase the issue:
main.html
{% if page.is_homepage %}
{% for page in nav.pages %}
{% if not page.is_homepage %}
{% include "article.html" %}
{% endif %}
{% endfor %}
{% else %}
{% include "article.html" %}
{% endif %}
The idea is that article.html can render every article on the homepage, but
also the individual articles on their own pages. MkDocs will create a global
variable page for you with the title, content, and URL. I mentioned I also
wanted a permalink:
article.html
<a href="{{ page.url | url }}">{{ page.title }}</a>
{{ page.content }}
The | url filter is supposed to make the URL relative to the current page.
However, the way that works does not look at the URL currently being rendered,
only at the existence of a page object scoped to the template file. Since my
main template was overriding page, each instance of the article template
thought it was being rendered under its own URL. The end result was every
permalink on the main page pointed to... the main page! (./). I fixed this by
renaming the page variable to article.
main.html
{% if page.is_homepage %}
{% for article in nav.pages %}
{% if not article.is_homepage %}
{% include "article.html" %}
{% endif %}
{% endfor %}
{% else %}
{% include "article.html" %}
{% endif %}
article.html
{% if not article %}
{# We are in a specific article, not the homepage #}
{% set article = page %}
<a href="{{ base_url }}">← Back home</a>
{% endif %}
<h1>
<a href="{{ article.url | url }}">{{ article.title }}</a>
</h1>
{{ article.content }}
As a bonus, this lets me branch on whether we are on the main page or not on the article template and add a handy "Back home" button.
Where we go from here
The point of doing this is that if I want to publish thoughts in a longer form than say, a mastodon post, it's low effort to get the words out there. It's possible I never end up writing anything other than this post, and that would be fine too.