How to back up a server with the 3-2-1 rule (and actually restore)
This guide walks through a server backup setup that survives real failures: a dead disk, ransomware, a dropped database, an incident in the data centre. It is written for anyone running a Linux VPS or dedicated server with a typical web stack, and everything below uses standard tools: rsync, cron, mysqldump, pg_dump. The goal is not just to have backups, but to be able to restore from them under pressure.
What the 3-2-1 rule actually means
Keep 3 copies of your data, on 2 different systems, with 1 copy offsite. The live data on the server counts as the first copy. A second copy in another directory on the same disk is not a backup, it dies together with the disk. A copy on a separate machine protects you against hardware failure. The offsite copy protects you against everything that hits the whole location at once: fire, flooding, a compromised account, ransomware that encrypts everything the server can reach.
A practical minimum for a single server: the live data, a nightly copy pushed to a backup host, and an encrypted copy in a different physical location or at a different provider. That already satisfies 3-2-1 without any commercial software.
What to back up: data, configs and dumps, not the whole disk
Full disk images are rarely worth it for a standard Linux server. The operating system can be reinstalled in minutes, so back up what is actually unique:
- Application data: /var/www, /home, upload directories.
- Configuration: /etc, including the web server, PHP, mail, cron jobs, TLS certificates and keys.
- Database dumps produced by the database itself (next section).
- Custom scripts in /usr/local/bin or /opt, plus the package list.
Save the package list so you can rebuild the same environment quickly:
dpkg --get-selections > /var/backups/packages.txt
One common mistake: copying /var/lib/mysql file by file while the database is running. Such a copy is inconsistent and often will not start at all after a restore. Databases are backed up with dump tools, not with cp.
rsync to a second location with cron
rsync transfers only what changed, so nightly runs are cheap even for large trees. Push over SSH with a dedicated key that can only log in as the backup user on the target. A minimal script:
#!/bin/sh set -eu DEST="backup@backup1.example.net:/backups/web01" rsync -az --delete /etc/ "$DEST/etc/" rsync -az --delete /var/www/ "$DEST/www/" rsync -az /var/backups/db/ "$DEST/db/"
The -a flag preserves permissions, owners and timestamps, -z compresses in transit, and --delete makes the target an exact mirror. Understand what --delete implies: if files get deleted or encrypted on the server, the next run mirrors that damage too. This is exactly why the target must keep its own history (see retention below) instead of holding a single mirror.
Schedule it with cron, after the database dump job:
20 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Check the log now and then, or better, alert on a non-zero exit code. A backup job that has been silently failing for 3 months is a common find during incident recovery.
Database dumps with mysqldump and pg_dump
For MySQL or MariaDB with InnoDB tables:
mysqldump --single-transaction --quick --routines --triggers \ --all-databases | gzip > /var/backups/db/mysql-$(date +%F).sql.gz
--single-transaction produces a consistent dump without locking tables, so the application keeps working while the dump runs.
For PostgreSQL, either everything at once:
sudo -u postgres pg_dumpall --clean | gzip > /var/backups/db/pgsql-$(date +%F).sql.gz
or one database in custom format, which allows selective restore of individual tables:
sudo -u postgres pg_dump -Fc shopdb > /var/backups/db/shopdb-$(date +%F).dump
Run the dumps 15 to 30 minutes before the rsync job so every offsite copy contains a fresh dump.
Retention and encryption for offsite copies
A single copy of yesterday is not enough. Data corruption is often noticed days or weeks later, and then you need a copy from before the damage. A sane default: keep 7 daily, 4 weekly and 6 monthly copies. On the backup host, expire old dumps with find:
find /backups/web01/db -name "*.sql.gz" -mtime +14 -delete
Anything that leaves hardware you control must be encrypted. age is the simplest modern option:
age -r age1examplepublickey0000000000 -o mysql-2026-07-21.sql.gz.age mysql-2026-07-21.sql.gz
gpg with a key pair works just as well. Keep the private key off the server: if an attacker takes the server, they should not also gain the ability to read your offsite archives. And test decryption at least once, because an encrypted backup with a lost key is not a backup either.
Test restores quarterly and treat snapshots as a bonus
An untested backup is a hope, not a plan. Once a quarter, run a real restore drill: create a clean test server, restore configs and data, load the database dump, and open the application against the test instance. Check row counts in the key tables and a few known records. Time the whole drill: that number is your actual recovery time, and on the first attempt it is usually 2 to 3 times worse than expected.
gunzip -t mysql-2026-07-21.sql.gz gunzip -c mysql-2026-07-21.sql.gz | mysql
Provider snapshots are convenient for rolling back before a risky upgrade, but they are not a backup strategy. A snapshot lives on the same infrastructure, in the same location, under the same account as the server itself. If the account is compromised, the storage fails, or the data centre has a serious incident, the snapshot disappears together with the original data. Snapshots fail both the "2 different systems" and the "1 copy offsite" parts of 3-2-1. Use them as an extra convenience layer on top of real backups, never instead of them.
The offsite leg does not have to be expensive. A small VPS in a different data centre than your primary server makes a perfectly good rsync target with a few hundred gigabytes of storage. And if you prefer to own the backup hardware, placing your own machine via server colocation in our Tier 3+ facility in Riga gives you a second location on independent infrastructure. Whichever target you pick, the rules stay the same: 3 copies, 2 systems, 1 offsite, and a restore drill every quarter.