Add comprehensive system backup scripts
Implement full system backup with Restic including: - Docker volume exports (Gitea, Jellyfin, Nextcloud, Portainer) - System configuration backup (/etc/) - Package list exports (pacman explicit, all, AUR) - Automated retention policy (7 daily, 4 weekly, 3 monthly, 1 yearly) - Separate temporary directories for Docker and system data
This commit is contained in:
95
scripts/backup-homelab.sh
Executable file
95
scripts/backup-homelab.sh
Executable file
@@ -0,0 +1,95 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Backup Docker volumes and system configs to NAS using Restic
|
||||||
|
# Can be run manually or via systemd timer
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
BACKUP_REPO="/mnt/nas/backups/homelab-restic"
|
||||||
|
PASSWORD_FILE="/home/hoborg/creds/restic-password.txt"
|
||||||
|
LOG_FILE="/var/log/homelab-backup.log"
|
||||||
|
DOCKER_BACKUP_DIR="/tmp/docker-backup-$$"
|
||||||
|
|
||||||
|
# Export password
|
||||||
|
export RESTIC_PASSWORD_FILE="$PASSWORD_FILE"
|
||||||
|
|
||||||
|
# Logging function
|
||||||
|
log() {
|
||||||
|
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
log "========================================"
|
||||||
|
log "Starting Homelab Backup"
|
||||||
|
log "========================================"
|
||||||
|
|
||||||
|
# Check if repository exists
|
||||||
|
if ! restic -r "$BACKUP_REPO" snapshots &>/dev/null; then
|
||||||
|
log "ERROR: Backup repository not initialized. Run backup-init.sh first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create temporary directory for Docker volume exports
|
||||||
|
mkdir -p "$DOCKER_BACKUP_DIR"
|
||||||
|
log "Created temporary backup directory: $DOCKER_BACKUP_DIR"
|
||||||
|
|
||||||
|
# Export Docker volumes
|
||||||
|
log "Exporting Docker volumes..."
|
||||||
|
|
||||||
|
# Gitea
|
||||||
|
log " - Exporting Gitea data..."
|
||||||
|
docker run --rm -v gitea_gitea:/data -v "$DOCKER_BACKUP_DIR":/backup alpine \
|
||||||
|
tar czf /backup/gitea-data.tar.gz -C /data .
|
||||||
|
|
||||||
|
# Jellyfin
|
||||||
|
log " - Exporting Jellyfin config..."
|
||||||
|
docker run --rm -v jellyfin_jellyfin_config:/data -v "$DOCKER_BACKUP_DIR":/backup alpine \
|
||||||
|
tar czf /backup/jellyfin-config.tar.gz -C /data .
|
||||||
|
|
||||||
|
# Nextcloud data
|
||||||
|
log " - Exporting Nextcloud data..."
|
||||||
|
docker run --rm -v nextcloud_nextcloud_data:/data -v "$DOCKER_BACKUP_DIR":/backup alpine \
|
||||||
|
tar czf /backup/nextcloud-data.tar.gz -C /data .
|
||||||
|
|
||||||
|
# Nextcloud database
|
||||||
|
log " - Exporting Nextcloud database..."
|
||||||
|
docker run --rm -v nextcloud_nextcloud_db:/data -v "$DOCKER_BACKUP_DIR":/backup alpine \
|
||||||
|
tar czf /backup/nextcloud-db.tar.gz -C /data .
|
||||||
|
|
||||||
|
# Portainer
|
||||||
|
log " - Exporting Portainer data..."
|
||||||
|
docker run --rm -v portainer_data:/data -v "$DOCKER_BACKUP_DIR":/backup alpine \
|
||||||
|
tar czf /backup/portainer-data.tar.gz -C /data .
|
||||||
|
|
||||||
|
log "✓ Docker volumes exported"
|
||||||
|
|
||||||
|
# Run backup
|
||||||
|
log "Running Restic backup..."
|
||||||
|
restic -r "$BACKUP_REPO" backup \
|
||||||
|
--verbose \
|
||||||
|
--tag homelab-docker \
|
||||||
|
--tag homelab-configs \
|
||||||
|
/etc/nginx/sites-available/homelab \
|
||||||
|
/etc/systemd/system/copyparty.service \
|
||||||
|
/home/hoborg/.config/copyparty/ \
|
||||||
|
"$DOCKER_BACKUP_DIR"
|
||||||
|
|
||||||
|
# Cleanup temporary files
|
||||||
|
log "Cleaning up temporary files..."
|
||||||
|
rm -rf "$DOCKER_BACKUP_DIR"
|
||||||
|
|
||||||
|
# Prune old backups (keep: 7 daily, 4 weekly, 6 monthly, 2 yearly)
|
||||||
|
log "Pruning old backups..."
|
||||||
|
restic -r "$BACKUP_REPO" forget \
|
||||||
|
--keep-daily 7 \
|
||||||
|
--keep-weekly 4 \
|
||||||
|
--keep-monthly 6 \
|
||||||
|
--keep-yearly 2 \
|
||||||
|
--prune
|
||||||
|
|
||||||
|
# Show backup stats
|
||||||
|
log "Backup statistics:"
|
||||||
|
restic -r "$BACKUP_REPO" stats --mode restore-size
|
||||||
|
|
||||||
|
log "========================================"
|
||||||
|
log "Backup completed successfully!"
|
||||||
|
log "========================================"
|
||||||
128
scripts/backup-system-full.sh
Executable file
128
scripts/backup-system-full.sh
Executable file
@@ -0,0 +1,128 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Full system backup - packages, configs, and Docker volumes
|
||||||
|
# Can be run manually or via systemd timer
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
BACKUP_REPO="/mnt/nas/backups/homelab-restic"
|
||||||
|
PASSWORD_FILE="/home/hoborg/creds/restic-password.txt"
|
||||||
|
LOG_FILE="/var/log/homelab-backup.log"
|
||||||
|
DOCKER_BACKUP_DIR="/tmp/docker-backup-$$"
|
||||||
|
SYSTEM_BACKUP_DIR="/tmp/system-backup-$$"
|
||||||
|
|
||||||
|
# Export password
|
||||||
|
export RESTIC_PASSWORD_FILE="$PASSWORD_FILE"
|
||||||
|
|
||||||
|
# Logging function
|
||||||
|
log() {
|
||||||
|
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
log "========================================"
|
||||||
|
log "Starting Full System Backup"
|
||||||
|
log "========================================"
|
||||||
|
|
||||||
|
# Check if repository exists
|
||||||
|
if ! restic -r "$BACKUP_REPO" snapshots &>/dev/null; then
|
||||||
|
log "ERROR: Backup repository not initialized. Run backup-init.sh first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create temporary directories
|
||||||
|
mkdir -p "$DOCKER_BACKUP_DIR"
|
||||||
|
mkdir -p "$SYSTEM_BACKUP_DIR"
|
||||||
|
log "Created temporary directories"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 1. Export Package Lists
|
||||||
|
# ============================================
|
||||||
|
log "Exporting package lists..."
|
||||||
|
pacman -Qqe > "$SYSTEM_BACKUP_DIR/pacman-explicit.txt" # Explicitly installed packages
|
||||||
|
pacman -Qq > "$SYSTEM_BACKUP_DIR/pacman-all.txt" # All installed packages
|
||||||
|
pacman -Qqm > "$SYSTEM_BACKUP_DIR/aur-packages.txt" # AUR/foreign packages only
|
||||||
|
log "✓ Package lists exported ($(wc -l < $SYSTEM_BACKUP_DIR/pacman-explicit.txt) explicit, $(wc -l < $SYSTEM_BACKUP_DIR/aur-packages.txt) AUR)"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 2. Export Docker Volumes
|
||||||
|
# ============================================
|
||||||
|
log "Exporting Docker volumes..."
|
||||||
|
|
||||||
|
# Gitea
|
||||||
|
log " - Exporting Gitea data..."
|
||||||
|
docker run --rm -v gitea_gitea:/data -v "$DOCKER_BACKUP_DIR":/backup alpine \
|
||||||
|
tar czf /backup/gitea-data.tar.gz -C /data .
|
||||||
|
|
||||||
|
# Jellyfin
|
||||||
|
log " - Exporting Jellyfin config..."
|
||||||
|
docker run --rm -v jellyfin_jellyfin_config:/data -v "$DOCKER_BACKUP_DIR":/backup alpine \
|
||||||
|
tar czf /backup/jellyfin-config.tar.gz -C /data .
|
||||||
|
|
||||||
|
# Nextcloud data
|
||||||
|
log " - Exporting Nextcloud data..."
|
||||||
|
docker run --rm -v nextcloud_nextcloud_data:/data -v "$DOCKER_BACKUP_DIR":/backup alpine \
|
||||||
|
tar czf /backup/nextcloud-data.tar.gz -C /data .
|
||||||
|
|
||||||
|
# Nextcloud database
|
||||||
|
log " - Exporting Nextcloud database..."
|
||||||
|
docker run --rm -v nextcloud_nextcloud_db:/data -v "$DOCKER_BACKUP_DIR":/backup alpine \
|
||||||
|
tar czf /backup/nextcloud-db.tar.gz -C /data .
|
||||||
|
|
||||||
|
# Portainer
|
||||||
|
log " - Exporting Portainer data..."
|
||||||
|
docker run --rm -v portainer_data:/data -v "$DOCKER_BACKUP_DIR":/backup alpine \
|
||||||
|
tar czf /backup/portainer-data.tar.gz -C /data .
|
||||||
|
|
||||||
|
log "✓ Docker volumes exported"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 3. Run Backup
|
||||||
|
# ============================================
|
||||||
|
log "Running Restic backup..."
|
||||||
|
restic -r "$BACKUP_REPO" backup \
|
||||||
|
--verbose \
|
||||||
|
--tag full-system \
|
||||||
|
--exclude '/etc/shadow*' \
|
||||||
|
--exclude '/etc/gshadow*' \
|
||||||
|
--exclude '/etc/passwd-' \
|
||||||
|
--exclude '/etc/group-' \
|
||||||
|
/etc/ \
|
||||||
|
"$DOCKER_BACKUP_DIR" \
|
||||||
|
"$SYSTEM_BACKUP_DIR"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 4. Cleanup
|
||||||
|
# ============================================
|
||||||
|
log "Cleaning up temporary files..."
|
||||||
|
rm -rf "$DOCKER_BACKUP_DIR"
|
||||||
|
rm -rf "$SYSTEM_BACKUP_DIR"
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 5. Prune Old Backups
|
||||||
|
# ============================================
|
||||||
|
log "Pruning old backups..."
|
||||||
|
restic -r "$BACKUP_REPO" forget \
|
||||||
|
--keep-daily 7 \
|
||||||
|
--keep-weekly 4 \
|
||||||
|
--keep-monthly 3 \
|
||||||
|
--keep-yearly 1 \
|
||||||
|
--prune
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 6. Show Stats
|
||||||
|
# ============================================
|
||||||
|
log "Backup statistics:"
|
||||||
|
restic -r "$BACKUP_REPO" stats --mode restore-size
|
||||||
|
|
||||||
|
log "========================================"
|
||||||
|
log "Full system backup completed!"
|
||||||
|
log "========================================"
|
||||||
|
log ""
|
||||||
|
log "Backed up:"
|
||||||
|
log " - /etc/ (all system configs)"
|
||||||
|
log " - Docker volumes (Gitea, Jellyfin, Nextcloud, Portainer)"
|
||||||
|
log " - Package lists (pacman + AUR)"
|
||||||
|
log ""
|
||||||
|
log "To restore packages after reinstall:"
|
||||||
|
log " pacman -S --needed \$(cat pacman-explicit.txt)"
|
||||||
|
log " yay -S --needed \$(cat aur-packages.txt)"
|
||||||
Reference in New Issue
Block a user