Skip to main content

SSH Backup with Rsync

rsync over SSH is a reliable way to move backups to another server. It supports resumable transfers, preserves metadata, and can be made safe-by-default (no deletion until you trust the pipeline).

Quick Summary
  • Prefer rsync over scp for repeatable offsite copies.
  • Start without --delete.
  • Use a dedicated SSH key and restricted backup user.
  • Verify: list remote files and compare checksums.

Prerequisites

  • A remote server with enough space.
  • SSH access to the remote.
  • rsync installed on both ends.
check-rsync-installed.sh
rsync --version
ssh -V

Set up SSH key-based access

Generate a dedicated key:

generate-backup-ssh-key.sh
ssh-keygen -t ed25519 -f ~/.ssh/wp-backup -C "wp-backup"

Copy the public key to the remote backup user:

install-ssh-key-on-remote.sh
ssh-copy-id -i ~/.ssh/wp-backup.pub backup@backup-host

Push backups to the remote (safe default)

This copies local backups to the remote without deleting anything.

rsync-push-backups-safe.sh
rsync -az \
-e 'ssh -i ~/.ssh/wp-backup -o StrictHostKeyChecking=accept-new' \
--info=stats2,progress2 \
/backups/ \
backup@backup-host:/srv/wp-backups/site-a/

Exclude unnecessary artifacts

Exclude nested archives and temporary files.

rsync-push-with-excludes.sh
rsync -az \
-e 'ssh -i ~/.ssh/wp-backup -o StrictHostKeyChecking=accept-new' \
--exclude '*.tmp' \
--exclude '*.partial' \
--exclude '*.bak' \
/backups/ \
backup@backup-host:/srv/wp-backups/site-a/

Mirror mode (with deletion)

warning

--delete removes files on the remote that do not exist locally. If your local disk is missing files, --delete can propagate the loss.

Only use mirror mode when you intentionally want the remote to track local state:

rsync-push-mirror-with-delete.sh
rsync -az \
--delete \
-e 'ssh -i ~/.ssh/wp-backup -o StrictHostKeyChecking=accept-new' \
/backups/ \
backup@backup-host:/srv/wp-backups/site-a/

Verification

List remote files:

verify-remote-files-over-ssh.sh
ssh -i ~/.ssh/wp-backup backup@backup-host 'ls -lah /srv/wp-backups/site-a | sed -n "1,80p"'

Checksum verification (example with sha256):

checksum-verify-local-vs-remote.sh
cd /backups
sha256sum wp-files-*.tar.* wp-db-*.sql.* | tail -n 10 > /tmp/local.sha256

scp -i ~/.ssh/wp-backup /tmp/local.sha256 backup@backup-host:/tmp/local.sha256
ssh -i ~/.ssh/wp-backup backup@backup-host 'cd /srv/wp-backups/site-a && sha256sum -c /tmp/local.sha256'

Restore direction (pull from remote)

If the VPS is rebuilt, you can pull backups down:

rsync-pull-backups-from-remote.sh
sudo mkdir -p /backups
sudo rsync -az \
-e 'ssh -i ~/.ssh/wp-backup -o StrictHostKeyChecking=accept-new' \
backup@backup-host:/srv/wp-backups/site-a/ \
/backups/

Next steps

  • Retention and pruning: opt/docker-data/apps/docusaurus/site/docs/server/linux-server/10-backup-disaster-recovery/rotation--retention-policies.mdx.
  • Permissions for backup storage: opt/docker-data/apps/docusaurus/site/docs/server/linux-server/10-backup-disaster-recovery/storage-permissions.mdx.