Skip to content

Automated Backup Strategies

Master the art of automated backups for your Raspberry Pi! This comprehensive guide covers everything from simple file backups to complete system imaging, ensuring your data and configurations are always protected with minimal manual intervention.

Introduction

Data loss is one of the most devastating problems that can affect any computing system, and Raspberry Pi projects are no exception. Whether it's SD card corruption, hardware failure, or accidental deletion, having a robust backup strategy is essential for maintaining project continuity and protecting valuable data.

Benefits of Automated Backups

Implementing automated backup strategies provides:

  • Data Protection: Safeguard against hardware failures and corruption
  • Quick Recovery: Minimize downtime with fast restoration processes
  • Version Control: Track changes and revert to previous configurations
  • Peace of Mind: Confidence that your work is always protected
  • Reduced Manual Work: Automated processes require minimal intervention
  • Compliance: Meet data retention and backup requirements

Backup Strategy Planning

1. Assess Your Backup Needs

Before implementing any backup solution, evaluate:

# Analyze disk usage
df -h
du -sh /home /etc /var /opt

# Identify critical data
find /home -type f -size +10M
find /etc -name "*.conf" -o -name "*.cfg"

# Check database sizes (if applicable)
sudo du -sh /var/lib/mysql 2>/dev/null
sudo du -sh /var/lib/postgresql 2>/dev/null

2. Define Backup Requirements

Backup Type Frequency Retention Priority
System Configuration Daily 30 days High
User Data Hourly 7 days High
Application Data Daily 14 days Medium
Complete System Image Weekly 4 weeks Medium
Logs Daily 7 days Low

3. Choose Backup Destinations

1
2
3
4
5
6
7
8
9
# Local storage options
lsblk  # List block devices
sudo fdisk -l  # List all disks

# Network storage setup
sudo apt install nfs-common cifs-utils sshfs

# Cloud storage preparation
sudo apt install rclone awscli

File-Level Backup Solutions

1. Rsync-Based Backups

Basic Rsync Setup

1
2
3
4
5
6
7
8
9
# Install rsync (usually pre-installed)
sudo apt install rsync

# Create backup directory structure
sudo mkdir -p /backup/{daily,weekly,monthly}
sudo mkdir -p /backup/exclude

# Create exclude file
sudo nano /backup/exclude/rsync-exclude.txt

Rsync exclude file:

# System directories to exclude
/dev/*
/proc/*
/sys/*
/tmp/*
/run/*
/mnt/*
/media/*
/lost+found

# Cache and temporary files
.cache/*
.thumbnails/*
*.tmp
*.log
*.swp

# Large unnecessary files
*.iso
*.img

Daily Backup Script

# Create daily backup script
sudo nano /usr/local/bin/daily-backup.sh

Daily backup script:

#!/bin/bash


# Configuration
SOURCE_DIR="/"
BACKUP_ROOT="/backup/daily"
EXCLUDE_FILE="/backup/exclude/rsync-exclude.txt"
LOG_FILE="/var/log/backup.log"
DATE=$(date +%Y%m%d)
HOSTNAME=$(hostname)

# Create backup directory
BACKUP_DIR="$BACKUP_ROOT/$DATE"
mkdir -p "$BACKUP_DIR"

# Function to log messages
log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

log_message "Starting daily backup to $BACKUP_DIR"

# Perform incremental backup
rsync -avH \
    --delete \
    --delete-excluded \
    --exclude-from="$EXCLUDE_FILE" \

--link-dest="$BACKUP_ROOT/latest" \
    "$SOURCE_DIR" \
    "$BACKUP_DIR/" 2>&1 | tee -a "$LOG_FILE"

# Check rsync exit status
RSYNC_EXIT_CODE=$?
if [ $RSYNC_EXIT_CODE -eq 0 ]; then
    # Update latest symlink
    rm -f "$BACKUP_ROOT/latest"
    ln -s "$DATE" "$BACKUP_ROOT/latest"
    log_message "Backup completed successfully"

    # Cleanup old backups (keep 7 days)
    find "$BACKUP_ROOT" -maxdepth 1 -type d -name "20*" -mtime +7 -exec rm -rf {} \;
    log_message "Cleanup completed"
else
    log_message "Backup failed with error code $RSYNC_EXIT_CODE"
    exit 1
fi

# Send notification
if command -v mail >/dev/null; then
    echo "Daily backup completed on $HOSTNAME" | mail -s "Backup Status" admin@example.com
fi

Make script executable:

sudo chmod +x /usr/local/bin/daily-backup.sh

2. Network Backup Solutions

SSH/SCP Remote Backup

1
2
3
4
5
6
7
8
# Create SSH key for automated backups
ssh-keygen -t ed25519 -f ~/.ssh/backup_key -N ""

# Copy key to backup server
ssh-copy-id -i ~/.ssh/backup_key.pub user@backup-server

# Create remote backup script
sudo nano /usr/local/bin/remote-backup.sh

Remote backup script:

#!/bin/bash


REMOTE_HOST="backup-server"
REMOTE_USER="backupuser"
REMOTE_PATH="/backups/raspberry-pi"
SSH_KEY="/home/pi/.ssh/backup_key"
SOURCE_DIRS="/home /etc /var/log /opt"

# Create tar archive
BACKUP_FILE="backup-$(hostname)-$(date +%Y%m%d-%H%M%S).tar.gz"
tar -czf "/tmp/$BACKUP_FILE" $SOURCE_DIRS 2>/dev/null

# Upload to remote server
scp -i "$SSH_KEY" "/tmp/$BACKUP_FILE" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH/"

# Cleanup local file
rm "/tmp/$BACKUP_FILE"

# Cleanup old remote backups (keep 14 days)
ssh -i "$SSH_KEY" "$REMOTE_USER@$REMOTE_HOST" \
    "find $REMOTE_PATH -name 'backup-*.tar.gz' -mtime +14 -delete"

NFS Network Backup

# Install NFS client
sudo apt install nfs-common

# Create mount point
sudo mkdir -p /mnt/nfs-backup

# Add to fstab for automatic mounting
echo "backup-server:/export/pi-backups /mnt/nfs-backup nfs defaults,_netdev 0 0" | sudo tee -a /etc/fstab

# Mount NFS share
sudo mount /mnt/nfs-backup

# Create NFS backup script
sudo nano /usr/local/bin/nfs-backup.sh

3. Cloud Backup Solutions

Rclone Configuration

1
2
3
4
5
6
7
8
# Install rclone
curl https://rclone.org/install.sh | sudo bash

# Configure cloud storage
rclone config

# Create cloud backup script
sudo nano /usr/local/bin/cloud-backup.sh

Cloud backup script:

#!/bin/bash


CLOUD_REMOTE="gdrive"  # Name from rclone config
CLOUD_PATH="/raspberry-pi-backups/$(hostname)"
SOURCE_DIRS="/home /etc"
TEMP_DIR="/tmp/cloud-backup"
DATE=$(date +%Y%m%d)

# Create temporary directory
mkdir -p "$TEMP_DIR"

# Create backup archive
tar -czf "$TEMP_DIR/backup-$DATE.tar.gz" $SOURCE_DIRS

# Upload to cloud
rclone copy "$TEMP_DIR/backup-$DATE.tar.gz" "$CLOUD_REMOTE:$CLOUD_PATH/"

# Cleanup local temp files
rm -rf "$TEMP_DIR"

# Cleanup old cloud backups
rclone delete "$CLOUD_REMOTE:$CLOUD_PATH" --min-age 30d

System Image Backups

1. SD Card Imaging

Create Image Backup Script

# Create system imaging script
sudo nano /usr/local/bin/create-image-backup.sh

System imaging script:

#!/bin/bash


BACKUP_DIR="/backup/images"
DATE=$(date +%Y%m%d)
HOSTNAME=$(hostname)
IMAGE_FILE="$BACKUP_DIR/$HOSTNAME-$DATE.img"

# Create backup directory
mkdir -p "$BACKUP_DIR"

# Get root device
ROOT_DEVICE=$(df / | tail -1 | awk '{print $1}' | sed 's/p[0-9]*$//')

echo "Creating image backup of $ROOT_DEVICE to $IMAGE_FILE"

# Create compressed image
sudo dd if="$ROOT_DEVICE" bs=4M status=progress | gzip > "$IMAGE_FILE.gz"

if [ $? -eq 0 ]; then
    echo "Image backup completed successfully"
    ls -lh "$IMAGE_FILE.gz"

    # Cleanup old images (keep 4 weeks)
    find "$BACKUP_DIR" -name "*.img.gz" -mtime +28 -delete
else
    echo "Image backup failed"
    exit 1
fi

PiShrink Integration

1
2
3
4
5
6
7
# Download and install PiShrink
wget https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh
sudo chmod +x pishrink.sh
sudo mv pishrink.sh /usr/local/bin/

# Create shrinking backup script
sudo nano /usr/local/bin/shrink-backup.sh

Shrinking backup script:

#!/bin/bash


SOURCE_IMAGE="$1"
OUTPUT_DIR="/backup/compressed"

if [ -z "$SOURCE_IMAGE" ]; then
    echo "Usage: $0 <source-image>"
    exit 1
fi

mkdir -p "$OUTPUT_DIR"

# Copy image to working directory
WORK_IMAGE="$OUTPUT_DIR/$(basename "$SOURCE_IMAGE" .gz)"

if [[ "$SOURCE_IMAGE" == *.gz ]]; then
    gunzip -c "$SOURCE_IMAGE" > "$WORK_IMAGE"
else
    cp "$SOURCE_IMAGE" "$WORK_IMAGE"
fi

# Shrink image
/usr/local/bin/pishrink.sh "$WORK_IMAGE"

# Compress shrunk image
gzip "$WORK_IMAGE"

echo "Shrunk image created: $WORK_IMAGE.gz"

2. Incremental System Backups

BTRFS Snapshots (if using BTRFS)

1
2
3
4
5
# Install btrfs tools
sudo apt install btrfs-progs

# Create snapshot script
sudo nano /usr/local/bin/btrfs-snapshot.sh

BTRFS snapshot script:

#!/bin/bash


SNAPSHOT_DIR="/snapshots"
DATE=$(date +%Y%m%d-%H%M%S)

# Create snapshots directory
sudo mkdir -p "$SNAPSHOT_DIR"

# Create read-only snapshot
sudo btrfs subvolume snapshot -r / "$SNAPSHOT_DIR/root-$DATE"

# List snapshots
sudo btrfs subvolume list "$SNAPSHOT_DIR"

 - Cleanup old snapshots (keep 10)
SNAPSHOTS=($(sudo btrfs subvolume list "$SNAPSHOT_DIR" | awk '{print $9}' | sort))

SNAPSHOT_COUNT=$(sudo btrfs subvolume list "$SNAPSHOT_DIR" | wc -l)
if [ $SNAPSHOT_COUNT -gt 10 ]; then
    REMOVE_COUNT=$((SNAPSHOT_COUNT-10))
    # Remove old snapshots from list
    sudo btrfs subvolume list "$SNAPSHOT_DIR" | awk '{print $9}' | sort | head -$REMOVE_COUNT | \
    while read snapshot_name; do
        sudo btrfs subvolume delete "$SNAPSHOT_DIR/$snapshot_name"
    done
fi

Database Backups

1. MySQL/MariaDB Backups

# Create database backup script
sudo nano /usr/local/bin/mysql-backup.sh

MySQL backup script:

#!/bin/bash


DB_USER="backup_user"
DB_PASS="backup_password"
BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d)

mkdir -p "$BACKUP_DIR"

# Backup all databases
mysqldump -u"$DB_USER" -p"$DB_PASS" --all-databases --single-transaction \
    --routines --triggers > "$BACKUP_DIR/all-databases-$DATE.sql"

# Compress backup
gzip "$BACKUP_DIR/all-databases-$DATE.sql"

# Cleanup old backups (keep 7 days)
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +7 -delete

2. PostgreSQL Backups

# Create PostgreSQL backup script
sudo nano /usr/local/bin/postgres-backup.sh

PostgreSQL backup script:

#!/bin/bash


BACKUP_DIR="/backup/postgres"
DATE=$(date +%Y%m%d)

mkdir -p "$BACKUP_DIR"

# Backup all databases
sudo -u postgres pg_dumpall > "$BACKUP_DIR/all-databases-$DATE.sql"

# Compress backup
gzip "$BACKUP_DIR/all-databases-$DATE.sql"

# Cleanup old backups
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +7 -delete

Application-Specific Backups

1. Docker Container Backups

# Create Docker backup script
sudo nano /usr/local/bin/docker-backup.sh

Docker backup script:

#!/bin/bash


BACKUP_DIR="/backup/docker"
DATE=$(date +%Y%m%d)

mkdir -p "$BACKUP_DIR"

# Backup Docker volumes
docker run --rm -v docker_volume:/data -v "$BACKUP_DIR":/backup \
    alpine tar czf "/backup/docker-volumes-$DATE.tar.gz" /data


# Export container configurations
docker-compose config > "$BACKUP_DIR/docker-compose-$DATE.yml"

# Save running container states
docker ps --format "table Names\tImage\tStatus" > \
    "$BACKUP_DIR/running-containers-$DATE.txt"

2. Home Assistant Backups

# Create Home Assistant backup script
sudo nano /usr/local/bin/homeassistant-backup.sh

Home Assistant backup script:

#!/bin/bash


HA_DIR="/home/homeassistant/.homeassistant"
BACKUP_DIR="/backup/homeassistant"
DATE=$(date +%Y%m%d)

mkdir -p "$BACKUP_DIR"

# Stop Home Assistant
sudo systemctl stop home-assistant@homeassistant

# Create backup
tar -czf "$BACKUP_DIR/homeassistant-$DATE.tar.gz" -C "$HA_DIR" .

# Start Home Assistant
sudo systemctl start home-assistant@homeassistant

# Cleanup old backups
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +14 -delete

Automated Scheduling

1. Cron Configuration

# Edit crontab for root
sudo crontab -e

Example cron schedule:

# Daily file backup at 2 AM
0 2 * * * /usr/local/bin/daily-backup.sh

# Weekly system image at 3 AM Sunday
0 3 * * 0 /usr/local/bin/create-image-backup.sh

# Hourly user data backup
0 * * * * /usr/local/bin/user-backup.sh

# Daily database backup at 1 AM
0 1 * * * /usr/local/bin/mysql-backup.sh

# Cloud backup every 6 hours
0 */6 * * * /usr/local/bin/cloud-backup.sh

2. Systemd Timer Configuration

Create Backup Service

# Create backup service file
sudo nano /etc/systemd/system/daily-backup.service

Systemd service file:

1
2
3
4
5
6
7
8
[Unit]
Description=Daily Backup Service
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/daily-backup.sh
User=root

Create Backup Timer

# Create backup timer file
sudo nano /etc/systemd/system/daily-backup.timer

Systemd timer file:

[Unit]
Description=Daily Backup Timer
Requires=daily-backup.service

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target

Enable and start timer:

1
2
3
sudo systemctl enable daily-backup.timer
sudo systemctl start daily-backup.timer
sudo systemctl status daily-backup.timer

Backup Monitoring and Alerting

1. Backup Status Monitoring

# Create backup monitoring script
sudo nano /usr/local/bin/backup-monitor.sh

Backup monitoring script:

#!/bin/bash


BACKUP_DIRS="/backup/daily /backup/weekly /backup/mysql"
ALERT_EMAIL="admin@example.com"
WARNING_HOURS=25  # Alert if backup older than 25 hours

for DIR in $BACKUP_DIRS; do
    if [ -d "$DIR" ]; then
        LATEST=$(find "$DIR" -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -d' ' -f2-)
        if [ -n "$LATEST" ]; then
            AGE_HOURS=$(( ($(date +%s) - $(stat -c %Y "$LATEST")) / 3600 ))

            if [ $AGE_HOURS -gt $WARNING_HOURS ]; then
                echo "WARNING: Backup in $DIR is $AGE_HOURS hours old" | \
                    mail -s "Backup Alert: $HOSTNAME" "$ALERT_EMAIL"
            fi
        else
            echo "ERROR: No backups found in $DIR" | \
                mail -s "Backup Alert: $HOSTNAME" "$ALERT_EMAIL"
        fi
    fi
done

2. Backup Verification

# Create backup verification script
sudo nano /usr/local/bin/verify-backup.sh

Backup verification script:

#!/bin/bash


BACKUP_DIR="/backup/daily/latest"
TEST_FILES="/etc/passwd /etc/hostname /home/pi/.bashrc"

echo "Verifying backup integrity..."

for FILE in $TEST_FILES; do
    if [ -f "$BACKUP_DIR$FILE" ]; then
        echo "✓ $FILE exists in backup"

        # Compare checksums
        ORIG_SUM=$(md5sum "$FILE" | cut -d' ' -f1)
        BACKUP_SUM=$(md5sum "$BACKUP_DIR$FILE" | cut -d' ' -f1)

        if [ "$ORIG_SUM" = "$BACKUP_SUM" ]; then
            echo "✓ $FILE checksum matches"
        else
            echo "✗ $FILE checksum mismatch"
        fi
    else
        echo "✗ $FILE missing from backup"
    fi
done

Backup Restoration Procedures

1. File Restoration

# Create restoration script
sudo nano /usr/local/bin/restore-files.sh

File restoration script:

#!/bin/bash


usage() {
    echo "Usage: $0 <backup-date> <source-path> [destination-path]"
    echo "Example: $0 20240601 /home/pi/important.txt"
    exit 1
}


BACKUP_DATE="$1"
SOURCE_PATH="$2"
# Use source path as destination if not specified
if [ -n "$3" ]; then
    DEST_PATH="$3"
else
    DEST_PATH="$SOURCE_PATH"
fi

if [ -z "$BACKUP_DATE" ] || [ -z "$SOURCE_PATH" ]; then
    usage
fi

BACKUP_DIR="/backup/daily/$BACKUP_DATE"

if [ ! -d "$BACKUP_DIR" ]; then
    echo "Error: Backup directory $BACKUP_DIR not found"
    exit 1
fi

BACKUP_FILE="$BACKUP_DIR$SOURCE_PATH"

if [ ! -f "$BACKUP_FILE" ]; then
    echo "Error: File $BACKUP_FILE not found in backup"
    exit 1
fi

echo "Restoring $SOURCE_PATH from backup dated $BACKUP_DATE"
echo "Destination: $DEST_PATH"

# Create destination directory if needed
mkdir -p "$(dirname "$DEST_PATH")"

# Copy file from backup
cp "$BACKUP_FILE" "$DEST_PATH"

echo "Restoration completed"

2. System Restoration

# Create system restoration guide
sudo nano /usr/local/bin/restore-system.sh

System restoration script:

#!/bin/bash


echo "System Restoration Script"
echo "========================"
echo "This script provides guidance for system restoration"
echo ""

echo "1. For file-level restoration:"
echo "   sudo /usr/local/bin/restore-files.sh <date> <file-path>"
echo ""

echo "2. For complete system restoration from image:"
echo "   sudo dd if=/backup/images/system-backup.img.gz | gunzip | dd of=/dev/mmcblk0 bs=4M"
echo ""

echo "3. For database restoration:"
echo "   # MySQL: gunzip < backup.sql.gz | mysql -u root -p"
echo "   # PostgreSQL: gunzip < backup.sql.gz | sudo -u postgres psql"
echo ""

echo "4. For configuration restoration:"
echo "   sudo rsync -av /backup/daily/latest/etc/ /etc/"
echo ""

echo "WARNING: Always backup current system before restoration!"

Backup Strategy Examples

1. Home Server Backup Strategy

# Create comprehensive home server backup
sudo nano /usr/local/bin/homeserver-backup.sh

Home server backup:

#!/bin/bash


# Configuration
BACKUP_ROOT="/backup"
NAS_MOUNT="/mnt/nas"
CLOUD_REMOTE="gdrive:homeserver"

# Daily incremental backup
/usr/local/bin/daily-backup.sh

# Database backup
/usr/local/bin/mysql-backup.sh

# Copy to NAS
rsync -av "$BACKUP_ROOT/daily/latest/" "$NAS_MOUNT/pi-backup/"

# Weekly cloud sync
if [ "$(date +%u)" -eq 7 ]; then
    rclone sync "$BACKUP_ROOT/daily/latest" "$CLOUD_REMOTE"
fi

2. IoT Device Backup Strategy

# Create IoT device backup
sudo nano /usr/local/bin/iot-backup.sh

IoT device backup:

#!/bin/bash


# Minimal backup for IoT devices
CONFIG_DIRS="/etc /home/pi/.config"
DATA_DIR="/var/log /opt/iot-data"

# Create lightweight backup
tar -czf "/tmp/iot-backup-$(date +%Y%m%d).tar.gz" $CONFIG_DIRS $DATA_DIR

# Upload to cloud
rclone copy "/tmp/iot-backup-*.tar.gz" "cloud:iot-backups/"

# Cleanup
rm /tmp/iot-backup-*.tar.gz

Best Practices and Tips

1. Backup Best Practices

3-2-1 Rule: - 3 copies of important data - 2 different storage media - 1 offsite backup

Testing: - Regularly test restoration procedures - Verify backup integrity - Document restoration processes

Security: - Encrypt sensitive backups - Secure backup storage locations - Use appropriate access controls

2. Performance Optimization

1
2
3
4
5
6
# Optimize backup performance
echo "vm.dirty_ratio = 5" | sudo tee -a /etc/sysctl.conf
echo "vm.dirty_background_ratio = 2" | sudo tee -a /etc/sysctl.conf

# Use ionice for backup processes
ionice -c 3 nice -n 19 /usr/local/bin/daily-backup.sh

3. Storage Management

1
2
3
4
5
6
# Monitor backup storage usage
df -h /backup
du -sh /backup/*

# Create storage cleanup script
sudo nano /usr/local/bin/backup-cleanup.sh

Storage cleanup script:

#!/bin/bash


BACKUP_ROOT="/backup"
MAX_USAGE=80  # Maximum usage percentage

CURRENT_USAGE=$(df "$BACKUP_ROOT" | tail -1 | awk '{print $5}' | sed 's/%//')

if [ "$CURRENT_USAGE" -gt "$MAX_USAGE" ]; then
    echo "Backup storage usage at $CURRENT_USAGE%, cleaning up..."

    # Remove oldest daily backups first
    find "$BACKUP_ROOT/daily" -maxdepth 1 -type d -mtime +3 -exec rm -rf {} \;

    # Remove old compressed images
    find "$BACKUP_ROOT/images" -name "*.img.gz" -mtime +14 -delete

    echo "Cleanup completed"
fi

Troubleshooting Common Issues

1. Backup Failures

# Check disk space
df -h

# Check permissions
ls -la /backup

# Check cron logs
sudo journalctl -u cron

# Test backup script manually
sudo /usr/local/bin/daily-backup.sh

2. Network Backup Issues

1
2
3
4
5
6
7
8
# Test network connectivity
ping backup-server

# Test SSH connection
ssh -i ~/.ssh/backup_key user@backup-server

# Check NFS mount
sudo mount -t nfs backup-server:/path /mnt/backup

3. Performance Issues

1
2
3
4
5
6
7
8
9
# Monitor I/O during backup
sudo iotop

# Check system load
top
htop

# Monitor network usage
sudo nethogs

Conclusion

A well-planned and automated backup strategy is essential for protecting your Raspberry Pi projects and data. This comprehensive guide provides multiple approaches to backup automation, from simple file-level backups to complete system imaging.

Key takeaways:

  1. Implement Multiple Backup Types: Combine file-level, database, and system image backups
  2. Automate Everything: Use cron jobs or systemd timers for consistent backups
  3. Test Regularly: Verify backup integrity and practice restoration procedures
  4. Monitor and Alert: Set up monitoring to ensure backups are working
  5. Follow Best Practices: Implement the 3-2-1 rule and encrypt sensitive data

Remember that backup strategies should be tailored to your specific needs, considering factors like data importance, recovery time objectives, and available storage resources. Start with basic automated backups and gradually implement more sophisticated solutions as your requirements grow.

The investment in a robust backup strategy will pay dividends when you need to recover from hardware failures, data corruption, or other disasters. Your future self will thank you for implementing these automated backup solutions!