Running on my own hardware
The footer says served on-prem with ❤️ from Tripoli, Greece. This is the longer version of that line.
For most of its life this site ran on rented infrastructure — excellent, generous, free-tier infrastructure, but someone else’s computers all the same. Since September 2026 it runs on mine: a small virtual machine on a server at home, in Tripoli. Nothing about the pages you read changed. Where they come from did.
The box
The server is a home NAS running Unraid. The site does not run on the NAS directly — it lives in a dedicated Debian virtual machine, kept deliberately separate from everything else on the box. If the site’s software ever misbehaves, the blast radius is one disposable VM, not the machine that holds the family photos.
How you reach it without me opening a door
A home server on a residential line is normally a bad idea to expose to the internet: you would forward ports, punch a hole in the firewall, and publish your home IP address for anyone to probe. This site does none of that.
Instead the VM makes a single outbound connection to Cloudflare and holds it open — a tunnel. Requests for the site arrive at Cloudflare, as they always did, and are handed back down that tunnel to the box. No port is forwarded, no firewall is opened, and my home address is never published. From the outside there is nothing to find.
So Cloudflare is still the front door: it answers first, terminates the encryption, keeps the DNS, guards the admin area, and screens the contact form for robots. “On-prem” here means where the work happens, not who greets you at the door. That split is the whole trick — it keeps the reachability and safety of a big network while the actual serving happens on a machine I can put my hand on.
What runs there
Two things, in a handful of containers:
- The site itself, served by a small web server (Caddy) handing back the exact same pre-built files as before — byte for byte the same pages.
- A small program for the two things a static file cannot do: the contact form and the admin interface. This is the old cloud function, rewritten to run as an ordinary Node.js service on the box. The contact form now sends its mail out through my normal mail provider instead of a cloud-specific hook.
How a change gets there
Editing and building work as they did — write markdown, commit, let CI build and check it. What changed is the last step. The build no longer uploads the result to a cloud host; it hands it to a worker that lives on the box itself. That worker dials out to GitLab, pulls the finished site, and swaps it into place atomically, keeping the previous few versions so a rollback is one command. Nothing ever connects into my home to deploy — the box always reaches out.
Why bother
Three reasons, in order of honesty. Because I wanted to own the thing end to end — the site now lives on hardware I can point at. Because building it taught me more than reading about it would have. And because a site that exists entirely at a provider’s discretion is a site you are renting; this one I keep.
The honest trade-off
A home server behind a domestic internet line is not a global content network. If the power blips or the line drops, the site is down until they come back — there is no automatic failover. Cloudflare’s cache in front softens this a great deal, and the old cloud version is kept dormant as a break-glass I can switch back to by hand, but the box is now a genuine single point of failure. For a personal site that is a fair price, and the setup at least earns its keep: it comes back on its own after a reboot.
What it costs
It used to cost nothing — everything sat on free tiers. Now the marginal cost is a few watts: the server was already running for other reasons, and the site is a small tenant on it. Cloudflare’s front door is still free, and GitLab still hosts the code. So the bill is electricity and the standing responsibility of keeping a machine alive — which, it turns out, is most of the point.
For the full technical breakdown — the generator, the tests, the type — see the colophon.