Linux backups cheatsheet.
rsync
rsync -avh src/ dst/
rsync -avzh src/ user@host:/dst/
rsync -avz --delete src/ dst/ # mirror
rsync -avz --partial --progress src dst
rsync -avz --exclude='*.log' src/ dst/
rsync -avz --link-dest=/previous src/ /new/ # hardlink-based incremental
restic
apt install restic
# Init
restic -r /backup init
restic -r s3:s3.amazonaws.com/bucket/path init
export RESTIC_PASSWORD_FILE=~/.restic-pass
# Backup
restic -r /backup backup /home /etc --exclude='*.tmp'
# List
restic -r /backup snapshots
restic -r /backup ls latest
# Restore
restic -r /backup restore latest --target /restore
restic -r /backup restore latest --include /etc
# Mount (browse)
mkdir /mnt/restic
restic -r /backup mount /mnt/restic
# Prune
restic -r /backup forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6
restic -r /backup prune
borg
apt install borgbackup
borg init --encryption=repokey /backup
borg create /backup::"{hostname}-{now}" /home /etc
borg list /backup
borg extract /backup::archive-name
borg prune /backup --keep-daily=7 --keep-weekly=4 --keep-monthly=6
borg compact /backup
ZFS snapshots
zfs snapshot tank/home@2026-01-15
zfs list -t snapshot
zfs rollback tank/home@2026-01-15
zfs destroy tank/home@2026-01-15
zfs send tank/home@snap | ssh remote zfs recv backup/home
zfs send -i prev current | ssh remote zfs recv backup/home
Auto-snapshots: zfs-auto-snapshot package.
btrfs snapshots
btrfs subvolume snapshot /home /home/.snapshots/2026-01-15
btrfs subvolume list /home
btrfs send /home/.snapshots/2026-01-15 | ssh remote btrfs receive /backup
snapper automates snapshots.
tar
tar czf backup-$(date +%F).tar.gz /home /etc
tar -cf - dir | zstd -19 --long > backup.tar.zst
tar -cf - dir | ssh remote 'cat > backup.tar'
dd (block-level)
dd if=/dev/sda of=/dev/sdb bs=4M status=progress
dd if=/dev/sda | gzip > sda.img.gz
Cloud sync
# rclone
rclone copy /local s3:bucket/path
rclone sync /local s3:bucket/path --progress
# aws cli
aws s3 sync /local s3://bucket/path
# gsutil
gsutil rsync -r /local gs://bucket/path
# rsync over ssh
rsync -avz /local user@remote:/backup/
Database backups
Postgres
pg_dump -Fc -U postgres myapp > backup.dump
pg_dump -U postgres --schema-only myapp > schema.sql
pg_dumpall -U postgres > all.sql
# Restore
pg_restore -d myapp backup.dump
psql -d myapp < schema.sql
MySQL
mysqldump -uroot -p --single-transaction --routines --triggers myapp > backup.sql
mysqldump --all-databases > all.sql
MongoDB
mongodump --archive=backup.archive --gzip
mongorestore --archive=backup.archive --gzip
Redis
redis-cli BGSAVE
cp /var/lib/redis/dump.rdb backup-$(date +%F).rdb
Strategy: 3-2-1
- 3 copies of data.
- 2 different media.
- 1 offsite.
Encryption
# tar + gpg
tar czf - dir | gpg -c > backup.tar.gz.gpg
gpg -d backup.tar.gz.gpg | tar xzf -
# Or use restic/borg which encrypt natively
Retention
hourly: 24
daily: 7
weekly: 4
monthly: 12
yearly: forever
restic / borg support these directly.
Test restores
Untested backups = no backups. Schedule monthly restore drills.
restic -r /backup restore latest --target /tmp/test
diff -r /tmp/test/important /important
rm -rf /tmp/test
Cron
0 2 * * * /opt/backup.sh
Or systemd timer. Add healthchecks.io ping for monitoring.
Backup script template
#!/bin/bash
set -euo pipefail
BACKUP_DIR=/backup
DATE=$(date +%F-%H%M)
RETENTION_DAYS=14
mkdir -p $BACKUP_DIR
# Curl heartbeat
curl -fsS https://hc-ping.com/UUID/start
# DB
pg_dump -U postgres myapp | gzip > "$BACKUP_DIR/db-$DATE.sql.gz"
# Files
tar czf "$BACKUP_DIR/uploads-$DATE.tar.gz" /var/www/uploads
# Offsite
rclone copy "$BACKUP_DIR" b2:my-backups/
# Prune
find "$BACKUP_DIR" -name "*.gz" -mtime +$RETENTION_DAYS -delete
curl -fsS https://hc-ping.com/UUID
Common mistakes
- No offsite copy.
- Backups never tested.
- Encryption key only in backup (unrecoverable).
- Backup files world-readable.
- Backup includes DB tmp dir or socket.
- “Replica = backup” — replicates errors too.
Read this next
If you want my restic + healthchecks setup, it’s at rajpoot.dev .
Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .