The 3-2-1 backup strategy is the simplest rule in data protection that actually holds up: keep three copies of your data, on two different types of storage, with one of them offsite. That’s all there is to it. For a Linux server, it means in practice: the live data on the server, a local backup next to it, and a second backup somewhere else entirely, ideally with a different provider.
The rule sounds so obvious that people tend to nod and move on. That’s exactly why, on October 7, 2026, we didn’t just explain it on our own server, we checked it: we built a real backup with restic, pushed it across the internet to Helsinki, simulated a ransomware attack and restored everything. We also counted which of our own data actually meets the rule. Three findings up front:
1. An
rsync --deletemirror is not a backup. In our test it faithfully copied 20 out of 20 encrypted files to the target and overwrote the good versions. A snapshot backup with restic survived the same attack untouched.2. Our best backup satisfies 3-2-1 on paper, but the offsite copy can be deleted from the main server. An attacker with root gets all three copies.
3. The source code of this very blog was in no backup at all when we ran the test. Not in Git, not offsite, nowhere. We wouldn’t have noticed without writing this article.

What is the 3-2-1 backup strategy?
The rule is usually credited to photographer Peter Krogh, who described it in the mid-2000s for protecting digital photo archives. It caught on because you can remember it in one sentence and it still covers the three most common causes of data loss:
| Number | Meaning | Protects against |
|---|---|---|
| 3 copies | Original plus two backups | Failure of any single copy |
| 2 media | Two different storage types or systems | Faults that hit a whole class of device |
| 1 offsite | One copy in another location | Fire, theft, data center outage, suspended account |
The key word is copy. The original counts. So if you hear “three copies” and make three backups, you have four, and that’s fine. If you only have one backup, you have two copies and you’re one mishap away from loss: when the server dies, the backup is the last version left, and that’s exactly when it sometimes turns out it hasn’t run for weeks.
Why three and not two?
Two copies sound redundant but are fragile in practice. You usually need the backup precisely when the original is broken. At that moment there’s only one copy left, and any mistake during restore (wrong password, corrupted file, accidentally overwritten) is final. The third copy is insurance for the moment the second one is in use.
What does “two media” mean for a server?
The rule comes from a world of hard drives, DVDs and tapes. On a rented server, it’s more useful to think in separate systems than in physical media. Two folders on the same disk are one medium. A backup on a second disk in the same server is better, but still shares the power supply, the operating system and root access. For a server, “two media” sensibly means: one copy on the server (or its snapshot system) and one in a different storage system, such as a storage box, an S3-compatible object store or a second server.
What does “offsite” mean?
Offsite means: an event that hits the server must not also hit the offsite copy. Another data center of the same provider protects against fire and power loss. A different provider also protects against a suspended customer account, insolvency or a billing mix-up. And a target that the server itself cannot delete protects against an attacker who has root on the server. We’ll get to that last point shortly, because that’s exactly where our own setup had a hole.
Jeff Crume from IBM Technology on the 3-2-1 rule, immutability and why backups need testing. A clear, vendor-light introduction.
The 3-2-1 backup strategy on a Linux server: a concrete setup
Here’s a simple, affordable setup for a single Linux server, such as a VPS or a dedicated server:
| Copy | Where | How | Medium |
|---|---|---|---|
| 1 | Live data on the server | Files, database | Server disk |
| 2 | Local restic repository | Daily via cron job or systemd timer | Separate disk or volume (or, if necessary, the same disk) |
| 3 | Offsite restic repository | Daily, encrypted via SFTP or S3 | Different provider or data center |
The local copy is for everyday mishaps: a deleted file, a broken update, “what did the config look like yesterday?”. It’s fast, free and restores in seconds. The offsite copy is for disasters: server gone, account gone, attacker inside.
Why two repositories instead of one backup that you then copy? Because copying a backup also copies all its faults. Two independent backup runs into two separate repositories are more robust: if one is damaged, the other isn’t automatically damaged too.

Why we use restic
For server backups, three tools deserve serious consideration: restic, BorgBackup and Kopia. All three create snapshots with deduplication and encryption. We use restic because it’s a single binary with no dependencies, because it can back up directly to SFTP, S3, Backblaze B2 and many other targets, and because its repository format is openly documented.
| Tool | Strength | Weakness |
|---|---|---|
| restic | Single binary, many targets built in (SFTP, S3, B2, REST), very easy to use | No built-in scheduler, prune is memory-hungry on large repos |
| BorgBackup | Very efficient, mature, append-only enforceable over SSH | Target needs Borg or Borg-capable storage |
| Kopia | Has a GUI, per-folder policies | Younger, less common on servers |
| rsync | Available everywhere, fast | No versions, no encryption, a mirror rather than a backup |
| tar + gzip | Easy to understand | Every backup is full, no deduplication |
Install restic on Ubuntu and Debian from the package repositories:
sudo apt install restic
restic version
# restic 0.16.4 compiled with go1.22.2 on linux/amd64
That’s the version we got from the Ubuntu 24.04 package. Newer releases are available as binaries on GitHub, and restic self-update only works with the official binary, not the distribution package.
Step by step: implementing the 3-2-1 backup strategy with restic
Step 1: Set a password and store it safely
restic encrypts every repository with a password. Without that password the backup is worthless; there’s no back door. In our test, a wrong password produced exactly this one line:
Fatal: wrong password or no key found
So put the password in a file only root can read, and keep a second copy outside the server, for example in a password manager. This is the part of 3-2-1 almost everyone forgets: the backup is offsite, but the key to it lives only on the server that just burned down.
sudo install -m 600 /dev/null /root/.restic-pass
openssl rand -base64 32 | sudo tee /root/.restic-pass > /dev/null
Step 2: Create the local and offsite repositories
export RESTIC_PASSWORD_FILE=/root/.restic-pass
# Copy 2: local (ideally on its own volume)
restic init -r /srv/backup/restic
# Copy 3: offsite via SFTP, e.g. a storage box or second server
restic init -r sftp:backup@backup.example.com:/restic/myserver
For SFTP, restic uses your SSH access. The cleanest approach is a dedicated SSH key just for backups, with its own user on the target. Why that matters is covered in the section on deletability below.
Step 3: The first backup
restic -r /srv/backup/restic backup /etc /srv /home /var/backups/db
restic -r sftp:backup@backup.example.com:/restic/myserver backup /etc /srv /home /var/backups/db
Our measurements with this blog’s source code and images (756 files, 44.2 MiB), restic 0.16.4, backed up from our server in Nuremberg:
| Operation | Time | Result |
|---|---|---|
| First backup, local | 0.93 s | 31.3 MiB stored (compression saves 29%) |
| Create offsite repo (Nuremberg → Helsinki) | 5.3 s | |
| First backup, offsite | 15.9 s | 31.3 MiB transferred |
| Second backup, nothing changed | 2.7 s | 0 bytes new |
| Copy with one changed line in a new path | under 1 s | 110 KiB new, 32 KiB stored |
| Full restore from Helsinki | 3.5 s | 780 files and folders, diff -r identical |
| Restore a single file from Helsinki | 2.9 s | |
restic check --read-data offsite | 29.3 s | “no errors were found” |
The 110 KiB row is the heart of restic: we copied the entire folder to a different location, changed one line and backed it up. restic recognised the content and stored only what was actually new. That’s why you can back up daily without the repository exploding.
Step 4: Back up databases properly
You can’t simply copy a running database as files, or a half-written state ends up in the backup. Create a dump first, then back up the dump:
# PostgreSQL
sudo -u postgres pg_dumpall | gzip > /var/backups/db/postgres-$(date +%F).sql.gz
# MySQL / MariaDB
mysqldump --all-databases --single-transaction | gzip > /var/backups/db/mysql-$(date +%F).sql.gz
# SQLite (consistent even with an active writer)
sqlite3 /srv/app/data.db ".backup '/var/backups/db/app-$(date +%F).db'"
restic can also read a dump straight from a pipe, so it never lands unencrypted on disk:
sudo -u postgres pg_dumpall | restic -r /srv/backup/restic backup --stdin --stdin-filename postgres.sql
Step 5: Run it automatically
restic has no scheduler of its own. Start it from a cron job or, better, a systemd timer, which gives you logs in the journal and clean failure reporting. A simple script:
#!/bin/bash
# /usr/local/bin/backup.sh
set -euo pipefail
export RESTIC_PASSWORD_FILE=/root/.restic-pass
PATHS="/etc /srv /home /var/backups/db"
sudo -u postgres pg_dumpall | gzip > /var/backups/db/postgres.sql.gz
for REPO in /srv/backup/restic sftp:backup@backup.example.com:/restic/myserver; do
restic -r "$REPO" backup $PATHS --exclude-caches --tag daily
restic -r "$REPO" forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
done
And the crontab entry, with a lock against overlapping runs (the reasoning is in our cron job article):
30 3 * * * flock -n /run/backup.lock /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Step 6: Define retention
forget decides which snapshots to keep; --prune then deletes data no snapshot needs any more. A sensible default for servers:
| Option | Meaning |
|---|---|
--keep-daily 7 | one snapshot per day for the last 7 days |
--keep-weekly 4 | plus one per week for 4 weeks |
--keep-monthly 6 | plus one per month for 6 months |
Retention is a security decision, not just a question of disk space. More on that in the ransomware test.
A mirror is not a backup: our ransomware test
The most common misconception in data protection goes: “I rsync to a second server every night, so I have a backup.” We recreated exactly that. Twenty test files, mirrored to a target with rsync -a --delete. Then we encrypted all twenty originals, the way ransomware would, and simulated the next nightly run.
The result on the target, first bytes of the first file:
00000000: 5361 6c74 6564 5f5f Salted__
Salted__ is the header of a file encrypted with OpenSSL. The mirror did its job perfectly and took over all 20 encrypted files. The good versions are overwritten. A mirror protects against a dead disk, but not against anything that happens on the disk: deletion, overwriting, encryption, a broken update.

The same attack against restic: in a copy, we encrypted 50 of 198 article files and backed them up. restic reported matter-of-factly:
Files: 0 new, 50 changed, 148 unmodified
Added to the repository: 1.427 MiB (1.408 MiB stored)
A new snapshot containing the encrypted files, but the older snapshots stayed untouched. Restoring simply means picking the snapshot from before the attack.
restic -r /srv/backup/restic snapshots
restic -r /srv/backup/restic restore 98401217 --target /srv/restore
That’s why retention is a security question. With --keep-last 2 and a daily run, the last clean state is gone after two days. With seven days of retention, an attack that stays unnoticed for a week still leaves good snapshots behind. How long attacks really go unnoticed is described in A server hijacked for five days. Our rule of thumb: retain at least twice as long as it would realistically take you to notice an incident.

The gap almost nobody checks: can the server delete its own backup?
Now the part that surprised us. Our most important backup on this server is a nightly job that encrypts the configuration and data of our AI agents and writes it to three places. On paper it’s textbook 3-2-1, even with a built-in restore test on every run:
| Copy | Location | Provider |
|---|---|---|
| Original | Main server, Nuremberg | Hetzner |
| Backup 1 | Private Git repository | GitHub |
| Backup 2 | Second server, Helsinki | Hetzner, different data center |
| (Backup 3) | Our own file vault | runs on the same main server |
Two things stood out. First: the fourth location, which we had mentally filed as “offsite”, runs on the very server it’s supposed to protect. The domain resolves to the same IP address. That’s not an offsite copy, it’s a second folder with a web interface.
Second, and more important: the copy to Helsinki is uploaded via scp with the main server’s root key, and the same script prunes old versions there with ssh … rm. We checked whether the main server can delete on the backup target:
ssh root@backup-target 'touch /root/test/x && rm /root/test/x && echo DELETE-POSSIBLE'
# DELETE-POSSIBLE
So the rule collapses as soon as someone has root on the main server. An attacker with those rights can read in the backup script where backups go, and already holds the right key. One command, and the “offsite” copy is gone just like the original.
How to do it better:
- A dedicated user on the target, not root. With its own key that exists only for backups.
- Append-only. The server may write new snapshots but not delete old ones. With restic, use rest-server with
--append-only; with Borg, useborg serve --append-onlyinauthorized_keys. Pruning (forget --prune) then runs from the backup target or a third machine, never from the server being backed up. - Object storage with Object Lock (S3-compatible): objects are immutable for a set period, even for the account owner.
- Pull instead of push: the backup server fetches the data, and the production server has no access to the backup target at all.
That’s precisely the extension commonly called 3-2-1-1-0 today: one copy additionally immutable or offline (the second 1), and zero errors in restore tests (the 0).
A hands-on beginner’s walkthrough of restic: init, backup, snapshots and restore to USB, network storage and the cloud.
What we found on our own server
We didn’t just check the agent backup; we counted which data on the server is backed up at all. The picture is mixed, and it’s probably typical of any server that has grown over months:
| Data | Backed up? | Where | Meets 3-2-1? |
|---|---|---|---|
| Agent configuration and memory | Daily, encrypted, with restore test | GitHub + Helsinki | almost (target deletable) |
| Game database (SQLite) | Daily, with integrity check | Local only, 16 versions | No, no offsite copy |
| App backend (SQLite) | Daily, with rotation | Local only | No |
| Self-hosted tool (PostgreSQL) | Hourly, by the tool itself | Local only, last dump Oct 2 | No, and no new version for five days |
| Other PostgreSQL databases (8) | No dump found | – | No |
| This blog’s source code (175 MB) | No | – | No |
| Blog editorial planning | Daily file copy | Local only | No |
Three lessons:
A backup that depends on a service dies with the service. The self-hosted tool wrote exemplary hourly dumps. Then the service was stopped on October 2, and the backups stopped with it. 149 dumps totalling 317 MB sit on the same disk, and nobody noticed that no new ones were arriving. Database dumps belong in a job that’s independent of the application.
“It’s in the repository” is only true if there is a repository. The blog source isn’t a Git repository. We’d mentally ticked it off as “it’s stored somewhere”. It was stored in exactly one place, which is exactly zero backups.
Local copies are the 2, not the 1. Most of our backups are well built, with integrity checks and rotation, but they live on the same disk as the data. They help against a deleted directory, not against a lost server.
We changed nothing in the running backups during the test. Moving to append-only and adding the missing data is a deliberate decision, not a side fix made while writing an article.
RAID, snapshots, cloud sync: what counts as a copy?
Many things look like a backup and aren’t. A quick classification:
| Technique | Counts as a backup copy? | Why |
|---|---|---|
| RAID 1/5/6 | No | Mirrors every fault instantly, including deletion and encryption. Only protects against disk failure. |
| Provider snapshot (VPS) | Partly | Great for quick rollbacks, but sits with the same provider and often in the same account. Counts as a local copy, not offsite. |
| ZFS/Btrfs snapshots | Partly | Protects against deletion and overwriting, not disk death or fire. Local copy. |
| Dropbox, Nextcloud, OneDrive sync | No | Syncs deletions and encryption too. Trash and version history help only so much. |
| rsync —delete to a second server | No | A mirror, see our test above. |
rsync with --link-dest (dated folders) | Yes | Every run is its own version; hard links save space. The classic solution before restic. |
| restic, Borg, Kopia | Yes | Versioned, encrypted, deduplicated snapshots. |
| External USB drive, unplugged afterwards | Yes, offline | The classic “air gap”, if done regularly. |
Our server itself has no RAID, and that’s fine for a cloud server: the provider stores the virtual disk redundantly. That doesn’t replace a backup either, for the same reason as RAID.
Test your restores: a backup without a restore test is a rumour
The 0 in 3-2-1-1-0 stands for “zero errors when restoring”. It’s the step most often missing in practice, because it doesn’t feel like work while everything is fine. Three levels, from quick to thorough:
# 1. Structural check (seconds)
restic -r REPO check
# 2. Actually read all data and verify checksums
restic -r REPO check --read-data
# or, for large repos, a subset per run:
restic -r REPO check --read-data-subset=1/10
# 3. Real restore and comparison
restic -r REPO restore latest --target /tmp/restore-test
diff -r /srv /tmp/restore-test/srv && echo "Restore identical"
For us: 44 MiB back from Helsinki in 3.5 seconds, diff -r identical, check --read-data in 29 seconds without errors. Larger repositories take longer, which is why --read-data-subset is handy: read a tenth each night, and after ten days everything has been checked once.

The most important test isn’t technical, though: can you perform the restore on an empty machine, without the old server? You need the repository password, access to the backup target and a note on which paths go where. If any of those lives only on the server, your backup is locked when you need it. A good drill every few months: new small VPS, install restic, restore from the offsite repo, start the service. It takes an hour and exposes every gap.
How much does a 3-2-1 backup strategy cost?
Less than most people think. For a typical small server with 50 to 200 GB of data:
| Item | Typical cost |
|---|---|
| Local copy | €0 (existing disk) or an extra volume for a few euros a month |
| Offsite copy: storage box / SFTP storage | From a few euros a month for 1 TB with European providers |
| Offsite copy: S3-compatible object storage | A few euros per TB per month, plus retrieval fees depending on provider |
| restic, Borg, Kopia | Free, open source |
| Time | One afternoon to set up, then a restore test every few months |
Prices change constantly, so check them directly with the provider. More important than price is the choice: if the offsite copy is with the same provider as the server, it protects against hardware failure and fire, but not against a suspended customer account. If you want to be safe, use a second provider for the offsite copy.
Thanks to deduplication, a restic repository with typical server data (configuration, code, database dumps) grows each day only by the actual changes. In our example, one changed line cost 32 KiB of storage.
3-2-1 for small businesses, homelabs and Nextcloud
The rule stays the same; only the building blocks change:
Small business with one server and workstations: server as described above. Workstations ideally back up with restic or the OS backup tool to the server or a NAS (copy 2), and from there it goes offsite (copy 3). Important: an employee PC with write access to the backup target is an entry point for ransomware. Append-only applies here too.
Homelab with Proxmox: VMs are backed up via Proxmox Backup Server or vzdump (local), and restic or Borg additionally pushes the backups offsite. Background on virtualisation is in Proxmox vs ESXi.
Nextcloud: the data directory, a database dump and config.php belong together. Without the database dump the files are there, but shares, calendars and contacts aren’t. Which provider makes sense for Nextcloud itself is covered in our Nextcloud hosting comparison.
Docker servers: back up the volumes and compose files, not the images; those can be pulled again at any time. Databases in containers still need a dump, for example via docker exec db pg_dumpall. More on the structure in What is Docker.
Checklist: does your server really meet the 3-2-1 rule?
- Are there at least two backups in addition to the original?
- Is at least one in a different storage system, not just a different folder?
- Is at least one with a different provider or in a different location?
- Can the server delete its offsite backup? If so: append-only, Object Lock or pull.
- Are databases backed up as dumps, and does the dump run independently of the application?
- Are the password and credentials for the backup also stored outside the server?
- Does retention reach back further than an attack could go unnoticed?
- When was the last real restore test?
- Would you notice if the backup stopped running? A backup without an alert goes silent exactly when it stops.
- Is everything included? List all services and data directories once and tick them off against the backup paths. That’s how we spotted the blog source code.
If you’re setting up a new server right now, plan the backup from the start. The other basic steps are in Linux server setup.
Frequently asked questions
What does the 3-2-1 rule mean?
Three copies of your data (the original plus two backups), on two different storage types or systems, with one copy in another location. That way at least one copy survives the failure of a device, a fault affecting a whole storage type and damage to a site.
Does the original count as one of the three copies?
Yes. The rule means three copies in total: the working data plus two backups. More backups don’t hurt.
What is the 3-2-1-1-0 rule?
A modern extension: on top of 3-2-1, one copy is immutable or offline (against ransomware and attackers with admin rights), and restore tests run with zero errors. It closes exactly the gap we found on our own server: an offsite backup the server itself can delete.
Is RAID a backup?
No. RAID protects against a disk failure and does so by mirroring every change instantly, including deletions, overwrites and encryption. It improves availability but doesn’t replace a single backup copy.
Is a hosting provider snapshot enough?
As a local copy, yes; as an offsite copy, no. Provider snapshots sit with the same provider and usually in the same customer account. If the account is suspended or compromised, they go with it. For 3-2-1 you also need a backup elsewhere.
Is rsync a backup?
An rsync --delete to a target is a mirror, not a backup. In our test it took over 20 of 20 encrypted files and overwrote the good versions. rsync with --link-dest and dated target folders, on the other hand, creates real versions and is a usable backup.
restic or Borg: which is better?
Both are excellent. restic backs up directly to many targets (SFTP, S3, B2) and needs nothing special on the target. Borg is slightly more efficient and easy to restrict to append-only over SSH, but needs Borg on the target. We recommend restic to start with; if you run your own backup server, Borg is just as good.
How often should I back up a server?
As often as you can afford to lose data. For most servers, daily is enough; databases with many changes are dumped hourly. The underlying question is your Recovery Point Objective: how many hours of work can you afford to lose?
How long should I keep backups?
At least long enough that an unnoticed attack or mistake still lies before the oldest snapshot. A good default: 7 daily, 4 weekly and 6 monthly versions. If you have legal retention obligations, those periods apply on top.
Do I need to encrypt backups?
As soon as a copy leaves the building: yes. restic and Borg always encrypt. But keep the password outside the server too, or your backup will be unreadable after a total loss.
How do I test that my backup works?
restic check --read-data verifies that all data is readable. The real test, though, is an actual restore, ideally on a fresh machine without access to the old server. Only then do you know the password, credentials and instructions are truly complete.
Conclusion: the 3-2-1 backup strategy is easy to remember and easy to miss
The rule itself is simple, and the tools are mature and free. In our test, restic managed a full restore from another country in three and a half seconds and shrugged off a simulated ransomware attack that defeated a classic rsync mirror.
The hard part isn’t the setup; it’s counting honestly. On our own server, the best-built backup met the rule only on paper, because the server can delete its own offsite copy. One database backup had quietly died with its service, and the source code of this blog wasn’t in any backup at all.
If you do only one thing after reading this, make it this: write down all the data that matters to you, and next to each item write where the second and third copies live and whether your server could delete them. The empty cells are your to-do list.