How to Back Up a Linux Server (rsync, tar and a Nightly Script)

Drives fail, rm -r happens in the wrong folder, and updates occasionally break things. A backup is the difference between an annoying hour and a lost year. You don't need fancy software: rsync to copy files, tar to bundle them, cron to do it every night, and a second drive or another machine to put them on.
Quick reference
| Task | Command |
|---|---|
| Mirror a folder to another drive | rsync -a --delete /home/ /mnt/backup/home/ |
| Dated archive of a folder | tar -czf /mnt/backup/etc-$(date +%F).tar.gz /etc |
| Dump a MariaDB/MySQL database | mysqldump --all-databases > /mnt/backup/db-$(date +%F).sql |
| Restore an archive | tar -xzf etc-2026-10-08.tar.gz -C / |
| Delete backups older than 30 days | find /mnt/backup -name "*.tar.gz" -mtime +30 -delete |
1. Decide what to back up
Not the whole disk — the operating system can be reinstalled in twenty minutes. Back up what you can't get back:
- /home — your files and scripts
- /etc — every config file you've edited
- /var/www — websites
- Databases — dumped with mysqldump, not copied as files
- Docker volumes — usually /var/lib/docker/volumes or wherever your compose files point
- A list of installed packages — dpkg --get-selections > packages.txt
2. rsync to a second drive
Mount a second drive (tutorial 22) at /mnt/backup, then:
sudo rsync -a --delete /home/ /mnt/backup/home/
sudo rsync -a --delete /var/www/ /mnt/backup/www/
-a preserves everything; --delete removes files from the backup that you've deleted from the source, so it stays an exact mirror. Trailing slashes on both sides. The first run copies everything; later runs take seconds.
To back up to another machine instead, use the SSH form: rsync -a --delete /home/ john@192.168.1.60:/backup/home/.
3. tar for configs and databases
A mirror is overwritten each night. For things where you might want last Tuesday's version, make dated archives:
sudo tar -czf /mnt/backup/etc-$(date +%F).tar.gz /etc
sudo mysqldump --all-databases | gzip > /mnt/backup/db-$(date +%F).sql.gz
$(date +%F) puts today's date in the filename. Clear old ones out automatically:
find /mnt/backup -name "*.gz" -mtime +30 -delete
4. Put it in a script
sudo nano /usr/local/bin/backup.sh
#!/bin/bash
set -e
DEST=/mnt/backup
DATE=$(date +%F)
rsync -a --delete /home/ $DEST/home/
rsync -a --delete /var/www/ $DEST/www/
tar -czf $DEST/etc-$DATE.tar.gz /etc
mysqldump --all-databases | gzip > $DEST/db-$DATE.sql.gz
dpkg --get-selections > $DEST/packages-$DATE.txt
find $DEST -name "*-20*" -mtime +30 -delete
echo "backup ok $DATE"
sudo chmod +x /usr/local/bin/backup.sh
sudo /usr/local/bin/backup.sh
5. Run it every night
sudo crontab -e
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Check /var/log/backup.log occasionally for "backup ok".
6. Test a restore
A backup you've never restored from is a hope, not a backup. Once:
mkdir ~/restore-test
tar -xzf /mnt/backup/etc-2026-10-08.tar.gz -C ~/restore-test
ls ~/restore-test/etc
If the files are there, you're covered.
Off-site
A fire or theft takes the backup drive with the server. Once a month, copy the latest archives to a USB drive you keep elsewhere, or to cloud storage with rclone (rclone sync /mnt/backup remote:server-backup). For versioned, encrypted, deduplicated backups to anywhere, look at restic — it's one binary and worth learning once the basics are working.
Troubleshooting
mysqldump asks for a password in cron. Put credentials in /root/.my.cnf ([client] / user=root / password=..., chmod 600).
The backup drive wasn't mounted and rsync filled the system disk. Add mountpoint -q /mnt/backup || exit 1 as the first line of the script.
Permission denied on some files. Run the script as root (root's crontab), as above.
Wrapping up
Mirror the files with rsync, archive configs and databases with tar and mysqldump, run it from cron at 2 am, and restore one file to prove it works. Then get a copy off-site. Two hours of setup for a server you can't lose.
