UN Uptime Notes
Monitoring & Backups

Backups that actually restore: the 3-2-1 rule for self-hosters

A silver and black external hard disk drive resting on a flat surface.
Photo: Nick / Unsplash

“I have backups” is one of the most confidently stated and least verified claims in self-hosting. Plenty of people have a cron job that runs pg_dump into a folder on the same disk as the database it's dumping — which is a backup in name only, because the one failure mode it doesn't protect against is the one most likely to actually happen: that disk dying.

The 3-2-1 rule isn't new or clever, but it's the simplest framework that forces you to notice gaps like that one before they cost you something.

The 3-2-1 rule, in one paragraph

Keep 3 copies of your data, on 2 different types of media, with 1 copy stored off-site. That's it. The number three matters because it means the original plus two backups, not the original plus one — a single backup is one bad day away from being zero backups. The media diversity matters because a flaw in one storage type (a bad batch of SSDs, a NAS firmware bug) shouldn't be able to take out every copy at once. The off-site copy matters because fire, theft, and "the landlord shut off power to the whole building" don't respect how careful you were with the other two.

Why “we have backups” usually means nothing

The most common failure we see in self-hosted setups isn't a missing backup — it's a backup that exists but was never going to survive the failure it's supposed to protect against:

  • A database dump written to a different folder on the same physical disk. Protects against accidental deletion, does nothing for disk failure.
  • A nightly rsync to a second drive in the same NAS. Protects against one drive failing, does nothing for the NAS itself being stolen, flooded, or struck by a power surge that takes both drives with it.
  • A backup that runs successfully according to its cron log, but hasn't actually been opened and restored in over a year, during which time the backup script silently started skipping a directory after a path got renamed.

Each of these technically satisfies "we have a backup." None of them satisfy 3-2-1, and more importantly, none of them have been proven to actually restore.

Picking your three copies

In practice, for a typical home server or small VPS setup, the three copies usually look like this: the live data on your server (copy one), a local backup on a second drive or a different machine on your network (copy two, different media type if you can manage it — e.g., SSD server, HDD backup target), and an off-site copy in cloud object storage or at a friend's house on a drive you swap periodically (copy three).

The "2 different media" part is the one people skip most often because it's the least convenient. If your server and your backup target are both consumer SSDs from the same batch, a firmware bug or a bad flash controller is a correlated failure, not an independent one. It doesn't need to be exotic — server on SSD, backup on spinning disk, is enough diversity to count.

Off-site storage worth paying for

This is the step people skip, because it's the one that costs actual money every month instead of a one-time hardware purchase. A few options that come up constantly in self-hosting communities, roughly cheapest to most full-featured:

  • Backblaze B2 — S3-compatible object storage, around $6/TB/month, no minimum retention fees. The default recommendation for "just give me cheap off-site storage I can point restic or rclone at."
  • rsync.net — built specifically for backup workflows (rsync, rclone, borg, restic all work natively), pricier per TB but with a long track record in the self-hosting world.
  • A drive at a friend or family member's house — genuinely zero monthly cost, the oldest form of off-site backup, and still completely valid as long as you actually rotate and test it rather than leaving a drive there once and forgetting about it.

Whichever you pick, encrypt before you upload, not after — tools like restic and borg handle this automatically, which is one more reason to use a tool built for backups rather than a raw rsync to a cloud bucket.

A close-up detail shot of a hard drive's internal components.
Photo: Liam Briese / Unsplash

Automating backups so nobody has to remember

A backup you have to remember to run manually is a backup that stops happening the week you're busy, sick, or on vacation — which is statistically also a good week for something to go wrong. A simple cron entry running a backup tool nightly, paired with a dead-man's-switch monitor (see our monitoring comparison — Healthchecks.io specifically is built for exactly this) that alerts you if the job didn't check in, closes the gap between "the backup script exists" and "the backup script is actually running."

Testing restores — the step everyone skips

Tip

Put a recurring calendar reminder, quarterly at minimum, to actually restore a backup to a throwaway environment and verify the data is intact and complete. An untested backup is a theory, not a backup.

This is the single highest-leverage thing in this entire post, and almost nobody does it. A backup that has never been restored might be missing a config file, might have been silently failing for the last six runs, or might restore to a state three versions behind what you think it is. The only way to know is to actually do it — spin up a throwaway container or VM, restore into it, and confirm the application actually starts and the data looks right, not just that the restore command exited with code 0.

A 3-2-1 plan you can copy this weekend

Concretely, for a typical self-hosted stack: nightly restic backups of your data and database dumps to a second local disk (copy two), a weekly sync of that same restic repository to Backblaze B2 (copy three, off-site), and a Healthchecks.io check-in on both jobs so a silent failure gets caught within a day instead of a year. Set a quarterly reminder to restore one backup end-to-end. That's a complete, genuinely defensible 3-2-1 setup, and most of it runs unattended once it's configured.