Backups and recovery

The 3-2-1 backup rule applied to a single VPS

· 9 min read

On this page (8)
  1. Who needs this
  2. What 3-2-1 means on one VPS
  3. Provider snapshots are a copy, not the copy
  4. The offsite choices
  5. Wire up two repositories
  6. Scope the credentials
  7. Mistakes we see
  8. FAQ

The 3-2-1 rule says keep three copies of your data, on two kinds of storage, with one copy offsite. It was written for offices with tape and NAS boxes, and it reads strangely when your whole business is one virtual server. What counts as a second kind of storage when the disk is a slice of someone else's SAN? Is the provider's snapshot a copy? This post turns the rule into a concrete layout for one VPS, with commands, and with the offsite choices compared on the things that matter.

3-2-1 on one VPS

The live VPS disk is backed up to a local second volume for fast restores and to an offsite bucket at another provider for survival.VPS diskcopy 1, liveSecond volumecopy 2, fast restoresOffsite bucketcopy 3, other providerresticrestic

Who needs this

A solo developer with one VPS and a nightly dump to the same disk. There is a backup file, so the box is ticked. A failed disk, a bad rm, a provider suspending the account or ransomware on the box all take the data and the dump together. One copy, wearing two names.

An agency hosting a few client sites on one server. Client data is not yours to lose. The server has provider snapshots switched on and nothing else. When a client asks "where are my backups kept, and who can touch them", the honest answer is "in the same account as the server".

A founder moving off a managed platform onto a VPS to save money. The platform did backups invisibly. On a VPS nothing is done until you do it, and the savings only exist if the replacement backup is at least as good.

Someone whose backups live on a second server that is also theirs and also on the same credentials. If one stolen SSH key or one compromised laptop can delete the data and the backup, you have two copies with one failure mode.

What 3-2-1 means on one VPS

Take the three numbers one at a time and ask what threat each one answers.

Three copies answers "one copy is damaged and I do not notice". The live data on the server is copy one. You need two more, because backups fail too, silently and often.

Two media answers a single technology failing: a bug in one storage system, one provider's outage, one kind of corruption. On a VPS you cannot count physical disks, so translate it to independent failure domains: a different machine, a different provider, a different storage system. The same SAN under two volumes does not count.

One offsite answers "the building burns". For a VPS the building is the provider's datacenter and, more commonly, your account with them. Offsite means a different provider, or at least a different account and region, with credentials that cannot be used to delete it from the production box.

A practical layout:

CopyWhereProtects againstTypical tool
1. LiveThe VPS disknothingthe app
2. Local or nearbyA second volume or the provider's snapshotrm -rf, bad deploy, bad migration, quick restoresrestic to a second disk, provider snapshot
3. OffsiteObject storage or another server at another providerprovider loss, account loss, ransomware, datacenter firerestic to s3:, b2:, sftp:

Copy two is for speed. Restoring from a volume attached to the same machine takes minutes and costs no egress. Copy three is for survival. If you can only afford one, make it three.

Provider snapshots are a copy, not the copy

Most VPS providers sell whole-disk snapshots, and they are good for what they are: quick rollback before a risky change, a fast way to clone a server. As the only backup they have four weaknesses:

  • They live in the same account, so account suspension, a billing dispute or a compromised console login removes them with the server.
  • They are crash-consistent at best for a running database, meaning you may restore a state that Postgres has to recover from, or SQLite caught mid-write.
  • They restore as a whole disk, so getting back one table or one deleted upload means mounting the whole thing somewhere.
  • Their retention is whatever the provider offers, not what you decide.

Provider snapshot vs a restic repository

Two cards: a provider snapshot lives in the same account and restores as a whole disk, while a restic repository elsewhere is encrypted and can restore single files.Provider snapshotSame account as the serverCrash-consistent at best for databasesRestores as a whole diskRetention is the provider's choicerestic repository elsewhereEncrypted before it leaves the boxDifferent account or providerYou choose the retentionDump inside is consistent

Keep them, as copy two. Do not stop at them. For the technique that gives you a consistent database copy to put in the repository, see a restic backup recipe for SQLite and Postgres.

The offsite choices

All of these work with restic, which encrypts on your machine before anything leaves it. That lowers the trust you need in the destination: a bucket provider that can read your files would still see only ciphertext.

Object storage (S3-compatible)

Backblaze B2, Cloudflare R2, Wasabi, Hetzner's object storage, AWS S3 and others speak a common protocol. Restic repository strings:

# S3-compatible endpoint
export RESTIC_REPOSITORY=s3:https://s3.example-provider.com/my-backups/vps1
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...

# Backblaze B2 native
export RESTIC_REPOSITORY=b2:my-backups:vps1
export B2_ACCOUNT_ID=...
export B2_ACCOUNT_KEY=...

You pay for stored gigabytes, usually per month, often with separate charges for API requests and for data leaving the provider. Pricing differs a lot and changes, so check the current page rather than trusting a number in a blog post. What stays stable is the structure of the bill:

  • Storage is cheap for the small data most single-VPS apps have.
  • Requests are negligible at one backup a day.
  • Egress, the cost of downloading, is what you pay at restore time. Some providers waive it or charge nothing within limits while others do not.
  • Minimum storage durations exist at a few providers, so deleting data early still bills for the minimum period. That interacts with retention, which is why it is worth reading before you pick a policy.

Rule of thumb: read the egress line before you pick a provider; you pay it on the worst day.

Good fit when: you want the least to maintain, you do not have a second server you trust, or your data is large enough that per-gigabyte pricing beats renting a machine.

SFTP to another server

export RESTIC_REPOSITORY=sftp:[email protected]:/srv/restic/vps1

This uses plain SSH and a host with disk. A cheap second VPS at a different provider, or a provider's storage-box product, fits. You pay a flat monthly price for a fixed amount of space and you own the box, which also means you patch it and watch its disk. For unattended runs you need a key without a passphrase (or an agent) and the host key in known_hosts. This is a combination the VPS Deploy & Backup Kit's own tests exercise: restic over SFTP against a real OpenSSH server, a repository that lands on the target, and a wrong path rejected.

Good fit when: you already run another server, or you want flat pricing and a restore that never pays for bandwidth.

rclone as a bridge

export RESTIC_REPOSITORY=rclone:myremote:vps1-backups

Restic can use any storage rclone supports, including consumer drives and obscure providers. It adds a dependency and one more thing that can break, so prefer a native backend when one fits.

Compared

OptionCost shapeRestore speedUpkeepWatch out for
S3-compatible bucketper GB-month plus requests, possible egressnetwork boundalmost noneegress fees, minimum retention, key scope
b2: nativeper GB-month, egress policies varynetwork boundalmost noneapplication keys, bucket settings
SFTP to a second serverflat per monthnetwork bound, no metered egressyou run the boxpatching, disk full, same-credentials trap
rclone remotedepends on remotedependsextra moving partone more dependency

Wire up two repositories

The simplest way to get copies two and three is two independent restic repositories, written by the same script with two configs. Independent means one broken repository cannot damage the other.

# /etc/backup-local.env
RESTIC_REPOSITORY=/mnt/volume2/restic
RESTIC_PASSWORD_FILE=/root/.restic-pass-local

# /etc/backup-offsite.env
RESTIC_REPOSITORY=s3:https://s3.example-provider.com/my-backups/vps1
RESTIC_PASSWORD_FILE=/root/.restic-pass-offsite
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...

Run the same script twice. The kit's backup.sh reads its settings from the file named in KIT_CONF, so two cron lines do it:

15 3 * * *  root  KIT_CONF=/etc/backup-local.env   /opt/vps-kit/backup.sh >> /var/log/backup-local.log   2>&1
45 3 * * *  root  KIT_CONF=/etc/backup-offsite.env /opt/vps-kit/backup.sh >> /var/log/backup-offsite.log 2>&1

Each run takes a fresh set of dumps, so the two repositories can hold slightly different moments, which is fine. Alternatively, run one backup and replicate with restic copy, which moves snapshots between repositories. It saves a second dump run but requires the destination repository to share the source's chunker parameters, so initialise it with restic init --copy-chunker-params --from-repo <source>. Two independent runs are simpler and have fewer shared failure modes. We use them.

Use different passwords for the two repositories if you prefer, and store both off the server. Each repository gets its own healthcheck ping so you hear when either one stops; see monitoring backups so silence is not success.

Scope the credentials

The offsite copy only protects you if an attacker on the VPS cannot delete it. The backup job runs on that VPS and holds the credentials, which makes the production box a path to the backups. Ways to reduce that:

  • Bucket-scoped keys. Create a key valid for one bucket only, never your account master key.
  • Versioning or object lock on the bucket, where the provider supports it. Deleted or overwritten objects stay recoverable for a period you set.
  • Append-only access. With restic's rest-server --append-only, a client can add snapshots but cannot remove data, and it is allowed to delete lock files. A key with no delete permission on a plain bucket makes restic's own lock cleanup fail, so test it before relying on it. The cost of append-only is that forget --prune has to run from somewhere trusted, not from the VPS.
  • A separate account or provider for copy three, with credentials never kept on the server beyond what the job needs.

None of this is exotic. It is the difference between "I have an offsite copy" and "I have an offsite copy that survives the thing that took out the server".

Mistakes we see

  • Counting provider snapshots as the offsite copy. Same account, same blast radius.
  • Backing up to a second disk on the same machine and calling it two media. It guards against disk failure, and nothing else on the list.
  • An offsite key with account-wide delete rights, stored in plain text on the VPS. A compromise of the VPS then removes both.
  • Never restoring from the offsite copy. Restoring from local copy two proves nothing about copy three: the credentials, the endpoint, the password. Restore from the offsite repository at least once.
  • Forgetting that egress is part of recovery. Know what a full download costs and how long it takes at your bandwidth before the day you need it.
  • Cron mail as the only alert. On most servers it goes to a local mailbox nobody reads.

FAQ

Is 3-2-1 overkill for a small app?

For a hobby project you can lose, yes. For anything with customer data or a revenue stream, the layout above costs a few repository strings and one bucket, which is small next to rebuilding from nothing. Start with one offsite repository and add the local copy later.

Does a provider snapshot count as one of the three copies?

It counts as a copy, but a weak one, because it shares the account and the failure domain with the server and is not guaranteed consistent for databases. Use it for convenience and rely on restic for survival.

How much does offsite storage cost?

It depends on your data size, your retention and the provider's pricing, which changes. For a small app the monthly bill is usually small, so the larger variable is egress at restore time. Estimate from your repository size with restic stats and compare two or three current price pages.

Should the offsite copy be at a different provider than the VPS?

Preferably. A different provider removes the shared account, billing and datacenter risks. If you stay at one provider, at least use a separate account and a different region.

Can restic back up to two places at once?

Not with one command. Run two backups with two configs, or replicate with restic copy. Two independent runs are simpler to reason about when something breaks.


If you want the dump, backup, retention and restore-test scripts without writing them, the VPS Deploy & Backup Kit takes any restic repository string in one config file, and the SFTP backend is covered by its test suite.

backuprestic