How I Backup

There is this old 3-2-1 rule for backups: 3 copies, 2 different media, 1 copy off site. I try to make sure my strategy at least fulfils this. Currently I have up to 6 copies, 5 devices, and 3 locations. It may sound like a lot to manage, but it is actually quite simple to setup and use if you know how to setup SSH access, use rsync1 and make simple bash scripts. Performing the backups themselves takes very little time, even though it's done manually.

To give some context, I start by explaining my previous strategy and then go on to explain my current one.

The previous strategy

There were a few things I was unhappy about:

What I did like:

The current setup

The new strategy is based around a few points:

Right now my devices are:

Every day items:

Rarely accessed, but want to keep long-term

Some thoughts on this setup

Reference script

The following script is what I use to backup every day items to my MacBook Pro, which is accessible over my local WiFi. I use very similar scripts for the partition, Vultr VPS, and Hetzner StorageBox (although rclone for the StorageBox).

#!/bin/bash

# Backup everyday folders to MacBookPro

# Folders:
# - .config
# - .ssh
# - bin
# - Dev
# - htdocs
# - log
# - Notes
# - Writing
# - Templates

# Files:
# - all dotfiles

# Configuration
REMOTE_PATH="eric@pro.local:/Users/eric/Backup-Everyday/"
LOG_FILE="/home/eric/log/backup-everyday.log"

# Function to log messages
log_msg() {
  printf "~/bin/bem: %s - %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$1" | tee -a $LOG_FILE
}

# Add timestamp to log entries
log_msg "Starting sync of everyday items to MacBookPro"

# Folders
## Notes: If subfolders like .config/nvim/ and its content should be included, all the directories until
## that path must be included for the file path to work for rsync.
## /.config/ means that the .config at the relative root is included, but not its content
rsync -avz \
  --include='/*' \
  --include='/.config/' \
  --include='/.config/rclone/' \
  --include='/.config/rclone/**' \
  --include='/.config/nvim/' \
  --include='/.config/nvim/**' \
  --include='/.config/Typora/' \
  --include='/.config/Typora/**' \
  --include='/.config/Code/' \
  --include='/.config/Code/**' \
  --include='/.ssh/**' \
  --include='/bin/**' \
  --include='/Dev/**' \
  --include='/htdocs/**' \
  --include='/log/**' \
  --include='/Notes/**' \
  --include='/Writing/**' \
  --include='/Templates/**' \
  --exclude='/.steam*' \
  --exclude='/.sudo_*' \
  --exclude='/snap' \
  --exclude='/tmp' \
  --exclude='**/node_modules' \
  --exclude='**/venv' \
  --exclude='**/.venv' \
  --exclude='**/taulag/tmp/**' \
  --exclude='*' \
  --prune-empty-dirs \
  /home/eric/ \
  "$REMOTE_PATH"

# Check for rsync errors
rsync_exit_code=$?
if [ $rsync_exit_code -ne 0 ]; then
  log_msg "Error: rsync failed with exit code $rsync_exit_code"
  printf "exiting due to error"
  exit 1
fi

log_msg "Finished successful sync to MacBookPro"
log_msg "----------"