#!/bin/bash # ============================================================================= # BorgBackup Pull-Script – läuft auf dem Raspberry Pi # Zieht Daten vom Docker-Host per sshfs und sichert sie lokal # ============================================================================= set -euo pipefail # ============================================================================= # KONFIGURATION – hier anpassen # ============================================================================= REMOTE_HOST="docker-host" # IP oder Hostname des Docker-Hosts REMOTE_USER="borgbackup" # SSH-User auf dem Docker-Host SSH_KEY="/home/borg/.ssh/borg_pull" # SSH-Key des borg-Users auf dem Pi MOUNT_POINT="/mnt/borg-pull/${REMOTE_HOST}" # Temporärer sshfs-Mountpunkt BORG_REPO="/media/backup/borg/${REMOTE_HOST}" # Lokales Borg-Repository auf dem Pi export BORG_PASSPHRASE="HIER-DEIN-PASSWORT" # Borg-Verschlüsselungspasswort # Was vom Docker-Host gesichert werden soll (Pfade auf dem Remote-Host) BACKUP_PATHS=( "etc" "/mnt/" "var/lib/docker/volumes" ) # Ausschlüsse (relativ zum Mountpunkt) EXCLUDES=( "--exclude" "${MOUNT_POINT}/var/lib/docker/volumes/*/tmp" "--exclude" "${MOUNT_POINT}/proc" "--exclude" "${MOUNT_POINT}/sys" "--exclude" "${MOUNT_POINT}/dev" "--exclude" "${MOUNT_POINT}/run" "--exclude" "${MOUNT_POINT}/tmp" "--exclude" "${MOUNT_POINT}/var/cache" "--exclude" "*.pyc" "--exclude" "*.log" ) # Aufbewahrungsrichtlinie KEEP_DAILY=7 KEEP_WEEKLY=4 KEEP_MONTHLY=6 LOG="/var/log/borg-pull-backup.log" # ============================================================================= # FUNKTIONEN # ============================================================================= log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG" } error_exit() { log "FEHLER: $*" cleanup exit 1 } cleanup() { log "Aufräumen..." if mountpoint -q "$MOUNT_POINT" 2>/dev/null; then log "Unmounte ${MOUNT_POINT}..." fusermount -u "$MOUNT_POINT" || umount "$MOUNT_POINT" || true fi } # Cleanup auch bei unerwarteten Fehlern trap cleanup EXIT ERR # ============================================================================= # HAUPTPROGRAMM # ============================================================================= log "============================================" log "Starte Pull-Backup von ${REMOTE_USER}@${REMOTE_HOST}" log "============================================" # --- 1. Voraussetzungen prüfen --- for cmd in borg sshfs fusermount ssh; do command -v "$cmd" &>/dev/null || error_exit "Programm nicht gefunden: $cmd" done [ -f "$SSH_KEY" ] || error_exit "SSH-Key nicht gefunden: $SSH_KEY" [ -d "$BORG_REPO" ] || error_exit "Borg-Repo nicht gefunden: $BORG_REPO – erst initialisieren!" # --- 2. Mountpunkt vorbereiten --- mkdir -p "$MOUNT_POINT" if mountpoint -q "$MOUNT_POINT"; then log "Vorheriger Mount gefunden, unmounte zuerst..." fusermount -u "$MOUNT_POINT" || true sleep 2 fi # --- 3. Docker-Host mounten (read-only!) --- log "Mounte ${REMOTE_HOST} nach ${MOUNT_POINT} (read-only)..." sshfs \ -o ro \ -o allow_other \ -o StrictHostKeyChecking=no \ -o IdentityFile="${SSH_KEY}" \ -o ServerAliveInterval=30 \ -o ServerAliveCountMax=3 \ -o reconnect \ "${REMOTE_USER}@${REMOTE_HOST}:/" \ "$MOUNT_POINT" \ || error_exit "sshfs-Mount fehlgeschlagen" log "Mount erfolgreich." # --- 4. Backup-Pfade zusammenbauen --- FULL_PATHS=() for p in "${BACKUP_PATHS[@]}"; do full="${MOUNT_POINT}/${p}" if [ -d "$full" ]; then FULL_PATHS+=("$full") log " Pfad gefunden: $full" else log " WARNUNG: Pfad nicht gefunden, wird übersprungen: $full" fi done [ ${#FULL_PATHS[@]} -gt 0 ] || error_exit "Keine gültigen Backup-Pfade gefunden!" # --- 5. Borg-Backup erstellen --- ARCHIVE_NAME="${REMOTE_HOST}-$(date '+%Y-%m-%dT%H-%M-%S')" log "Erstelle Archiv: ${ARCHIVE_NAME}" borg create \ --verbose \ --filter AME \ --list \ --stats \ --show-rc \ --compression lz4 \ --exclude-caches \ "${EXCLUDES[@]}" \ "${BORG_REPO}::${ARCHIVE_NAME}" \ "${FULL_PATHS[@]}" \ 2>&1 | tee -a "$LOG" BORG_EXIT=${PIPESTATUS[0]} case $BORG_EXIT in 0) log "Backup erfolgreich abgeschlossen." ;; 1) log "WARNUNG: Backup mit Warnungen abgeschlossen (Exit 1)." ;; *) error_exit "Backup fehlgeschlagen (Exit ${BORG_EXIT})." ;; esac # --- 6. Unmounten --- log "Unmounte ${MOUNT_POINT}..." fusermount -u "$MOUNT_POINT" log "Unmount erfolgreich." # Trap zurücksetzen, da wir selbst gemountet haben trap - EXIT ERR # --- 7. Alte Archive bereinigen --- log "Bereinige alte Archive (daily=${KEEP_DAILY}, weekly=${KEEP_WEEKLY}, monthly=${KEEP_MONTHLY})..." borg prune \ --list \ --glob-archives "${REMOTE_HOST}-*" \ --keep-daily "$KEEP_DAILY" \ --keep-weekly "$KEEP_WEEKLY" \ --keep-monthly "$KEEP_MONTHLY" \ "$BORG_REPO" \ 2>&1 | tee -a "$LOG" # --- 8. Repo komprimieren --- log "Komprimiere Repository..." borg compact "$BORG_REPO" 2>&1 | tee -a "$LOG" log "============================================" log "Pull-Backup abgeschlossen: ${ARCHIVE_NAME}" log "============================================"