The 3-2-1 backup rule
The 3-2-1 rule: three copies, two different media, one off site. It covers the three scenarios that destroy data: hardware failure, human error and ransomware. A provider snapshot is one copy, not a complete strategy.
The three dimensions
| Rule | What it protects against | Concrete example |
|---|---|---|
| 3 copies | accidental deletion, corruption | production, local archive, remote copy |
| 2 media | failure of one disk or storage | VPS SSD and separate object storage |
| 1 off site | loss of the provider or site | another machine, region or account |
A snapshot on the same storage as the VPS is not a second medium: if the storage disappears, both copies disappear. Backups included in the plan are useful, but do not replace a copy whose destination and retention you control.
Produce a usable copy
For files, a dated archive often suffices. For a database, the dump must be consistent: --single-transaction avoids an intermediate state.
sudo tar --one-file-system -czf /var/backups/www-$(date +%F).tar.gz /var/www /etc/nginx
mysqldump --single-transaction --routines --triggers -u backup -p base > /var/backups/base-$(date +%F).sqlBoth files stay on the VPS: only the first copy. Send them elsewhere with a tool that handles increments and integrity checks, such as restic:
export RESTIC_REPOSITORY=sftp:backup@backup-host:/srv/restic
restic init
restic backup /var/www /etc/nginx
restic checkThe restic password must not be stored in Git or in the cron script. Keep it in a root-only file (chmod 600) and back it up separately: without it, the repository is unreadable.
Encrypt and set retention
Encrypt before the copy leaves the server. age or gpg --symmetric --cipher-algo AES256 produce a file protected by a passphrase. Keep the decryption key apart from the backup, otherwise theft of the media gives access to both.
Set retention, for example 7 daily, 4 weekly and 6 monthly copies. Ensure purging never removes every copy from one day. If supported, enable immutability or append-only mode: ransomware that reaches the server must not encrypt mounted backups.
Test the restore
An untested backup is an assumption. Restore into a temporary directory without overwriting production:
restic restore latest --target /tmp/restore-test
restic check --read-data-subset=5%Open a random file, check the tree size, import the dump into a test database and start the application on a temporary port. Record the duration: that is your real recovery time, often much longer than estimated.
Mistakes that break the rule
- Backing up a database by copying MySQL files instead of a consistent dump.
- Keeping the encryption key on the same server as the copies.
- Letting a cron job fail silently for months.
- Restoring a backup without checking it predates the incident.
- Deleting old copies before validating the new one.
A cron job must log, return an explicit error code and alert on failure. A backup is measured by its restore, not its file size.
Advertisement
Was this article helpful?
Read next
- Apply security updatesUpdate Debian, understand the shared kernel and automate security fixes without surprise reboots.
- Protect accounts against phishingRecognise a fraudulent message, harden your access and respond methodically after a click.
- Understanding firewallsUnderstand inbound and outbound policies, then configure UFW on Debian without cutting SSH.