Colophon
This website has been hand-made using open source tools. This page explains a bit about how it all works, and lets me give credit to those tools.
Last updated: 22nd October 2025
Overview
The site is powered by a custom Go backend I wrote. It’s open source, because why not? The backend is fairly simple: mostly just pulling data out of the database and rendering it. It employs the following libraries:
- sqlx for database utility functions
- pq for connecting to the PostgreSQL database
- golang-migrate for handling database schema migration
- pgvector-go for dealing with vector types
- goldmark for rendering markdown into HTML
- chroma for syntax highlighting
- some of my own libraries for utility functions:
- envflag for receiving flag values from env vars
- slogflags for configuring the logging package
- middleware for doing a bunch of http stuff
The site is hosted on a Hetzner dedicated server, using Docker to run the services, and Docker Compose to manage them. The site’s backed by a PostgreSQL database with the pgvector extension. I also self-host a copy of Umami for statistics. The contact form sends an e-mail to me via Amazon SES.
Related posts
All the blog posts show three “related posts” at the bottom of the page. This was originally done by trying to match the tags applied to each post, but I’m really bad at tagging. When I rebuilt the site I switched to using vector embedding to calculate the similarity. This is a machine learning technique that basically encodes the “meaning” of a post as a very long vector. You can then calculate the similarity between vectors to find semantically related posts. To calculate those vectors, I call out to an ollama instance running the mxbai-embed-large model. This computation is very cheap, and runs entirely on CPU.
Styling
I hand-write all the CSS for the site, split up into lots of smaller files to keep it maintainable. The Go process then concatenates all of these together, and generates a hash of the contents, so it can present a single file that can be cached for a long time by clients.
The styling system also supports adding extra bits of styling depending on the current date. So on my birthday you might see a birthday hat and balloons, during December there will snow, etc.
Resources
The site uses three fonts:
- IBM Plex Sans for the main body text
- Berkeley Mono for code blocks
- Chris hand for titles, captions, etc. See Making a font of my handwriting for how I made it
The brand icons in the footer are from Simple Icons. The icons on the projects page are from Tabler.
AI use
All the written content on this website is made by hand, by me. I don’t believe AI has a place in human-to-human communication. I do, however, use LLMs as a proof reader/editor, and may sometimes bounce ideas off them. I also use them for some coding tasks, including some parts of the website backend here.
Privacy
Aside from the contact form which generates an e-mail to me, nothing you do on the site should be trackable by any third parties. Resources are all hosted locally, there are no invasive social media buttons, etc. I gather some stats about visitors, such as pages visited, country/region of origin, and referrer, but this does not include logging IP addresses or doing anything that could identify individuals. The stats are really only useful in aggregate. This may seem a bit overkill for a personal website, but it’s how I’d want my data to be treated on other sites.
Prior versions
This is the latest of many incarnations of my personal website. The most recent ones were:
- A static site using 11ty; you can see the latest code here.
- A static site using Hugo; you can see the latest code here
- A static site using Jekyll; you can see the latest code here.
I haven’t done enough digital archaeology to find earlier versions, but at one point there was a custom PHP backend, and at another point the entire site was a single XML FOAF file with some XSLT to make it pretty.