#!/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)"