diff --git a/scripts/borg-offsite.sh b/scripts/borg-offsite.sh new file mode 100755 index 0000000..cf19d82 --- /dev/null +++ b/scripts/borg-offsite.sh @@ -0,0 +1,90 @@ +#!/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"