#!/bin/bash # DocFast Off-site BorgBackup to Hetzner Storage Box # Runs AFTER local backup completes (cron: 03:30 UTC) # Same data & retention as local: 7 daily + 4 weekly + 3 monthly set -uo pipefail REMOTE_REPO="ssh://u149513-sub11@u149513-sub11.your-backup.de:23/./docfast-1" BACKUP_NAME="docfast-$(date +%Y-%m-%d_%H%M)" LOG_FILE="/var/log/docfast-backup.log" log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - [OFFSITE] $1" | tee -a "$LOG_FILE" } export BORG_PASSPHRASE="docfast-backup-$(date +%Y)" export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes export BORG_RSH="ssh -o StrictHostKeyChecking=no" # Prepare data (same as local backup script) TEMP_DIR="/tmp/docfast-backup-offsite-$$" mkdir -p "$TEMP_DIR" trap "rm -rf $TEMP_DIR" EXIT # PostgreSQL dump log "Dumping PostgreSQL..." export PGPASSFILE="/root/.pgpass" pg_dump -h localhost -p 5432 -U docfast -d docfast \ --no-password --clean --if-exists --format=custom \ > "$TEMP_DIR/docfast-db.dump" 2>>"$LOG_FILE" || log "WARNING: PostgreSQL dump failed" # Docker volumes mkdir -p "$TEMP_DIR/docker-volumes" cp -r /var/lib/docker/volumes/* "$TEMP_DIR/docker-volumes/" 2>/dev/null || true # Nginx mkdir -p "$TEMP_DIR/nginx" cp -r /etc/nginx/* "$TEMP_DIR/nginx/" 2>/dev/null || true # SSL mkdir -p "$TEMP_DIR/letsencrypt" cp -r /etc/letsencrypt/* "$TEMP_DIR/letsencrypt/" 2>/dev/null || true # Crontabs mkdir -p "$TEMP_DIR/crontabs" cp -r /var/spool/cron/crontabs/* "$TEMP_DIR/crontabs/" 2>/dev/null || true crontab -l > "$TEMP_DIR/crontabs/root-crontab.txt" 2>/dev/null || true # OpenDKIM mkdir -p "$TEMP_DIR/opendkim" cp -r /etc/opendkim/* "$TEMP_DIR/opendkim/" 2>/dev/null || true # App files mkdir -p "$TEMP_DIR/docfast-app" cp /opt/docfast/docker-compose.yml "$TEMP_DIR/docfast-app/" 2>/dev/null || true cp /opt/docfast/.env "$TEMP_DIR/docfast-app/" 2>/dev/null || true cp -r /opt/docfast/scripts "$TEMP_DIR/docfast-app/" 2>/dev/null || true cp -r /opt/docfast/deploy "$TEMP_DIR/docfast-app/" 2>/dev/null || true # System info mkdir -p "$TEMP_DIR/system" systemctl list-unit-files --state=enabled > "$TEMP_DIR/system/enabled-services.txt" 2>/dev/null || true dpkg -l > "$TEMP_DIR/system/installed-packages.txt" 2>/dev/null || true log "Starting off-site backup: $BACKUP_NAME" # Create remote backup borg create \ --stats \ --compression lz4 \ --exclude-caches \ "$REMOTE_REPO::$BACKUP_NAME" \ "$TEMP_DIR" 2>>"$LOG_FILE" || { log "ERROR: Off-site backup creation failed"; exit 1; } log "Off-site backup created, pruning..." # Prune (same retention as local) borg prune \ --list \ --prefix 'docfast-' \ --keep-daily 7 \ --keep-weekly 4 \ --keep-monthly 3 \ "$REMOTE_REPO" 2>>"$LOG_FILE" || log "WARNING: Off-site prune failed" # Compact borg compact "$REMOTE_REPO" 2>>"$LOG_FILE" || true log "Off-site backup completed: $BACKUP_NAME" borg info "$REMOTE_REPO" 2>>"$LOG_FILE"