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 .