It has been about six months since I started running services on my VPS. Time for an honest look at what worked, what did not, and what I would do differently.

What works well

Static sites are effortless. Hugo plus Nginx has been zero-maintenance. I deploy with a script, and it just works. No crashes, no updates to worry about, no dependencies to manage. This has been the most clearly worthwhile thing I self-host.

Uptime Kuma runs itself. I set it up once, and it has been quietly monitoring everything since. The only time I touch it is to add a new monitor. It has caught two outages that I would not have noticed otherwise.

Docker simplifies everything. Pinned image versions, isolated environments, easy rollbacks. I resisted containers for a while, thinking they were overkill for a single server. They are not. The overhead is minimal, and the operational benefits are real.

What did not work

I over-engineered the backup system. My initial backup setup involved multiple scripts, rotating snapshots, and offsite sync. It was fragile and I never fully trusted it. I replaced it with a single rsync cron job to an offsite location. Simpler and more reliable.

Trying too many services at once. In the first month, I installed half a dozen things to “try them out.” Most sat unused, consuming resources and needing updates. Now I only install something when I have an actual, immediate need for it.

What I would do differently

Start with monitoring from day one. I set up Uptime Kuma a few weeks in. I should have done it first. Knowing your server is up is more important than whatever service you are deploying on it.

Automate TLS renewal verification. Let’s Encrypt renewal worked fine automatically, but I did not have monitoring on the certificate expiry dates. A silent renewal failure would have meant a surprise expired certificate. Now Uptime Kuma checks certificate expiry for every HTTPS endpoint.

Keep a simple log of changes. I started doing this halfway through and wished I had done it from the start. A text file with dated entries like “installed Forgejo” or “updated Nginx config for gzip” makes troubleshooting much easier when something breaks weeks later.

The numbers

Current state of the server after six months:

  • 5 services running (Nginx, Uptime Kuma, Forgejo, LibreSpeed, WireGuard)
  • ~450 MB RAM used at idle
  • 99.7% uptime over the period (the 0.3% was a provider-side network issue)
  • 2 unplanned outages, both resolved within an hour

It is not a lot, but it runs quietly and does what I need. That feels like the right place to be.