Skip to main content

Local vs Remote Backups

Local backups are about speed. Remote backups are about surviving loss of the server. A WordPress VPS needs both: one local copy for fast restores and one remote/offsite copy for real disaster recovery.

Quick Summary
  • Local backups: fast restore, low bandwidth, but same failure domain as the VPS.
  • Remote backups: survive VPS loss, but restores can be slower and need bandwidth.
  • Recommended baseline: keep local + offsite, verify both, and practice restores.

Local backups

Local backups are stored on the same server or in the same provider account.

Good for:

  • Quick rollback after a bad plugin/theme update.
  • Fast restores when you accidentally delete files.
  • Minimizing restore time during an incident.

Risks:

  • If the VPS is wiped, compromised, or the disk fails, local backups can disappear too.
  • If backups are stored under the webroot, an attacker may download them.

Remote/offsite backups

Remote backups are stored outside the VPS failure domain.

Good for:

  • VPS loss (accidental destroy, billing issue, provider outage).
  • Ransomware or compromise (if remote storage is isolated and access is scoped).
  • Long-term retention.

Trade-offs:

  • Restores require network bandwidth and time.
  • You must manage credentials and encryption.

Treat the live site as one copy, then add:

  1. Local artifacts for fast restore
  • Files: /backups/wp-files-YYYY-MM-DD.tar.zst
  • Database: /backups/wp-db-YYYY-MM-DD.sql.zst
  1. Offsite artifacts for survivability
  • Remote storage (another VPS, object storage, or cloud drive) via rclone or rsync.

A safe workflow (local then remote)

Create local artifacts first, verify them, then copy offsite.

backup-local-then-remote.sh
set -euo pipefail

BACKUP_DIR="/backups"
STAMP="$(date +%F)"

FILES_ARCHIVE="$BACKUP_DIR/wp-files-$STAMP.tar.zst"
DB_DUMP="$BACKUP_DIR/wp-db-$STAMP.sql.zst"

mkdir -p "$BACKUP_DIR"

echo "creating files archive: $FILES_ARCHIVE"
tar -C /var/www/html -cf - . \
| zstd -3 -T0 -o "$FILES_ARCHIVE"

echo "creating db dump: $DB_DUMP"
mysqldump --single-transaction --quick --routines --events --triggers \
--databases wordpress \
| zstd -3 -T0 -o "$DB_DUMP"

echo "verifying artifacts"
zstd -t "$FILES_ARCHIVE"
zstd -t "$DB_DUMP"
ls -lh "$FILES_ARCHIVE" "$DB_DUMP"

echo "copying offsite"
rclone copy "$BACKUP_DIR" "remote:wp-backups" \
--include 'wp-*.tar.zst' --include 'wp-*.sql.zst'
warning

Do not run rclone sync until you understand what it deletes. Prefer rclone copy unless you intentionally want the remote to mirror local state.

Verification you should actually do

Local existence is not enough. Verify:

  • Integrity: zstd -t / gzip -t / xz -t.
  • Paths: list archive contents (does it contain what you expect?).
  • Restore drill: extract into a staging directory.
verify-local-files-archive.sh
tar --use-compress-program=zstd -tf "/backups/wp-files-$(date +%F).tar.zst" | sed -n '1,25p'

Remote verification:

verify-remote-backups.sh
rclone lsf "remote:wp-backups" | rg -n 'wp-(files|db)-'

Common mistakes

  • Storing backups under /var/www/html.
  • Keeping only local backups (not disaster recovery).
  • Keeping only remote backups (slow restores, higher downtime).
  • Backing up without doing restore drills.

Next steps

  • Define retention: see opt/docker-data/apps/docusaurus/site/docs/server/linux-server/10-backup-disaster-recovery/rotation--retention-policies.mdx.
  • Choose remote targets: see opt/docker-data/apps/docusaurus/site/docs/server/linux-server/10-backup-disaster-recovery/rclone-remote-targets.mdx.
  • Practice restores: see opt/docker-data/apps/docusaurus/site/docs/server/linux-server/10-backup-disaster-recovery/empty-2.mdx.