How to Own Your Backups When You Self-Host
A practical guide to owning your backups when you self-host: what to back up, where to store it, how to test restores, and why the vendor is not doing it for you.
The moment you leave managed cloud, backups become your job, and that is the part most people get wrong. They assume "self-hosted" and "unprotected" are the same thing. They are not. A backup you own and have tested is stronger than a backup a vendor promises but never lets you verify. Here is how I run backups across a fleet of boxes, and how you should too.
The rule is simple: back up the state, store it somewhere the server cannot reach and delete, and test the restore on a schedule. Everything else is detail.
What you actually need to back up
Not the whole server. You do not back up the operating system or the installed packages, because you can rebuild those from a script in minutes. You back up the state that cannot be regenerated.
That means databases first. A logical dump of Postgres, taken on a schedule, is the spine of the whole plan. Then user-uploaded files and object storage. Then the small configuration that is annoying to recreate: environment files, reverse proxy config, cron definitions. If your app writes it and a user would miss it, it goes in the backup. If you can produce it from a git repo or a setup script, it does not.
This is why I keep the state small and the rebuild scripted. When the machine itself is disposable, the backup only has to protect the irreplaceable part, which I get into in the deploy you actually control.
Where to store backups so they survive the box
A backup on the same server is not a backup. If the disk dies or the box gets compromised, it dies with everything else. The state has to leave the machine.
I push backups to object storage off the fleet, on a different provider from the one running the boxes. That separation matters: a billing problem or an account lockout should never be able to take out both your live server and your only copy. Encrypt the archive before it leaves the box, so the storage provider holds ciphertext and nothing else.
I use a restic-style workflow: deduplicated, encrypted, incremental snapshots pushed to a bucket on a schedule. Retention is tiered: keep the last several daily snapshots, a few weekly, a few monthly. That way a mistake you notice next week is still recoverable. This is the same discipline I apply to keeping the whole stack portable, which I laid out in what no vendor lock-in actually requires.
How to test a restore before you need it
A backup you have never restored is a hope, not a plan. This is the step everyone skips and the one that actually matters.
Once a month, take a snapshot and restore it to a throwaway box or a local container. Bring the database up. Point a copy of the app at it. Confirm the data is there and the app runs. Time how long it takes, because that number is your real recovery window, and you want to know it before an outage teaches it to you.
The first time I did this, the restore worked but took longer than I assumed, so I changed the dump format and cut it down. You only learn that by rehearsing. Owning your backups means owning the drill, not just the file.
Why the vendor was never really doing this for you
Managed platforms advertise backups, and technically they take them. But read what you actually get. Often the backup lives inside the same vendor, in a format you cannot export cleanly, restorable only back into their platform. That is not protection against the vendor. That is deeper lock-in wearing a safety vest.
Real ownership means the copy is portable and provider-independent: a plain encrypted archive you could restore onto any box, anywhere, tomorrow. If your backup only restores into the platform that holds your live data, you have one point of failure painted to look like two. I treat an independent, restorable copy as non-negotiable, for the same reason I keep servers that cannot be held hostage.
Make it boring and automatic
The whole system should run without you thinking about it. A cron job takes the dump, encrypts it, pushes it off-site, and rotates retention. A second job alerts you if a backup did not land when expected, because a silent backup failure is the worst kind. Then the monthly restore drill on your calendar as the one manual step.
This is exactly the kind of platform work you build once and every app inherits. I bundled backup jobs into my hosting stack, HostSSH, so a new app on the fleet is protected the day it ships instead of the day I remember to set it up.
Self-hosting does not mean going without a net. It means the net is yours, you know how it is knotted, and you have jumped into it on purpose to make sure it holds. Own the backup, store it off the box, and test the restore. Do those three and losing the server becomes an inconvenience instead of a catastrophe.