New site, new house
I've been thinking for years about designing a more minimalistic personal website that would live on its own Virtual Private Server (VPS).
Inertia kept me away from that desire. After all, I had a perfectly functional website using Jekyll, with no hosting costs at all. Moreover, due to a mix of circumstances, I've barely updated the site. So, why bother?
Things have finally changed this year. All I wanted was to update the about page of the previous website, but I was greeted by utterly broken ruby and Github actions build. The same had happened already last time I attempted a similar update. Given the time it took me to fix the build last time, I've wondered if it wouldn't be faster to simply build my own static website generator (SSG).
I've read many times on Hacker News comments of users that find much easier to roll out your own SSG, but using a pre-existing solution always felt like a more sane idea to me. Especially, because I really dislike dealing with frontend. Even basic HTML and CSS are enough to run me out of patience.
It's probably pretty easy to guess, at this point in time, I have used Large Language Models (LLM) to ublock me. LLMs have become really good at web development tasks, especially for the pervasive HTML and CSS. I haven't really attempted the so-called vibe coding using an LLM agent, because I still care about understanding how the code works. However, simply asking a chatbot, like ChatGPT, to bootstrap the design of a minimalistic page was already enough to get me moving and to take away the blockage a blank page can cause. With the big elephant in the room out of the way, I could finally stop thinking and actually move my personal page to a VPS.
Picking up a VPS provider
VPSes can be rented monthly by a fairly low amount of money (the cost of a coffee cup, for example). For less than 5 euros, you can get a virtual machine, in a shared server, with 2 vCPUs and 4GB of RAM memory, plus a public IP address. Such specification is more than enough for personal needs, such as hosting a personal static website.
I went with Hetzner, among the many options available. There are even cheaper options than Hetzner, but the fact it's a European provider based in Germany weighted heavy on my decision.
Registering with Hetzner was smooth. However, their automated system flagged my registration as a risky one (probably because I used an e-mail alias). I had to upload a photo of an ID for verification. It was during the weekend, so I had to wait until Monday to get my account verified, to finally become able to deploy a VPS. Thus, if you are the type of person paranoid about ID verification, I'd not recommend going with Hetzner. After receiving confirmation my account was verified, I could finally create a virtual machine for my VPS.
Deploying a VM
Hetzner has a basic configuration to bootstrap a VPS. The recommended configuration deals with the user creation, with the addition of packages to reinforce network access security and the necessary sshd_config to harden SSH access. All very simple and straightforward.
Unfortunately, for reasons I can't tell, the creation of the ssh configuration file did not work. It was just the first deployment and I was already locked out because the user should be only able to login via SSH. On the fortunate side, it was fairly easy to get into rescue mode and fix the configuration.
The Static Site Generator
I started asking ChatGPT for a minimalistic CSS and HTML design for a static personal page. I was also strict about my desire to avoid javascript completely. The first iteration already got me quite close to the current state of the site and gave me something to start working creating the html templates.
The templates have a base that contains placeholders for the page contents and, a header and a footer that are common to all pages. The other templates contain placeholders for the about, blog and articles pages.
The generator itself is less than 300 codes of Go. Replacing the placeholders is very simple and relies on Go's strings standard lib. The example below, shows how placeholders are replaced on an article template page.
func applyArticleTemplate(tpl string, a Article) string {
out := tpl
out = strings.ReplaceAll(out, "{{ title }}", a.Title)
out = strings.ReplaceAll(out, "{{ date_iso }}", a.DateISO)
out = strings.ReplaceAll(out, "{{ date_human }}", a.DateHuman)
out = strings.ReplaceAll(out, "{{ content }}", a.Content)
return out
}
I wanted the convenience of writing the articles using Markdown. Among the choices I've had for parsing Markdown, I've picked goldmark. There is no strong reason besides it looked simpler than markdown alternative. Parsing Markdown was easy, but I was still missing code highlight. I used an extension for goldmark, but it was not quite working as I expected. The extension relies on chroma CSS for code highlight, but wasn't generating the embedded CSS when the parser was configured as Standalone. Searching around, I learned it's possible to generate the chroma css files using hugo as below. It's a bit weird to have had to rely on hugo to generate those files, but I had hugo already installed nevertheless.
hugo gen chromastyles --style=dracula > dracula.css
In the end, I've finished with an easy to understand structure that looks like this.
.
├── content
│ ├── about.md
│ └── articles
│ └── migrating-from-github.md
├── deploy.sh
├── public
│ ├── blog
│ │ ├── index.html
│ │ └── migrating-from-github.html
│ ├── chroma.css
│ ├── dracula.css
│ ├── github.css
│ ├── index.html
│ └── styles.css
├── serve.sh
├── ssg
│ ├── go.mod
│ ├── go.sum
│ ├── main
│ └── main.go
└── templates
├── base.html
├── footer.html
├── header.html
└── pages
├── article.html
├── blog.html
└── index.html
The deploy and serve scripts are just for the convenience of deploying the website and serving it for local testing.
Some final words about the result
The current looks of the website are not what I would call beautiful, but it's functional and it's not at all unpleasant to read. (At least for me, I should ask for a second opinion). Considering I'm not thinking I've ever go viral or have a large reading audience, the current layout seems good enough for my needs of writing anything I feel like.
The use of an LLM for something simple and that I can understand well is just one good example of where its application makes sense. I'm quite neutral when it comes about people preaching about the wonders of the technology or about detractors. I do hope there will be a point when the hype will fade away, the necessary energy for the current desperate training will be reduced, crawlers will stop abusive behavior and, quite important, that strong regulations get in place to attempt preventing the bad headlines that vary from the production of fake news videos to causing harm to kids. However, I can't also deny that the technology in the hands of seasoned software development practictioners might free a lot of room to focus on real challenges while the LLM acts a super assistant that takes care of the boilerplate.
On the usability side of the SSG, I feel like markdown has complicated things a bit more than they should. Especially on the CSS side. However, it's a fair price to pay for the convenience of writing markdown.
Overall I'm pretty happy with the result. More importanly, I feel like after breaking my inertia, my brain is bubbling with ideas and with stuff I'd like to write. I can't promise and I'll be kind to myself if I turn out not writing as often as I'd like. Life is still happening out there!