#!/usr/bin/env bash # unifi-backup-sync.sh — Daily UniFi backup sync from old controller to Wasabi S3. # Source: root@178.156.131.57:/var/lib/unifi/backup/ # Target: s3://hermes-vps-backups/unifi-backups/ # Schedule: Daily at 2 AM ET via cron (no_agent) set -euo pipefail SSH_KEY="/root/.ssh/itpp-infra" SOURCE_HOST="178.156.131.57" SOURCE_PATH="/var/lib/unifi/backup" S3_BUCKET="s3://hermes-vps-backups/unifi-backups" ENDPOINT="https://s3.us-east-1.wasabisys.com" STAGE="/root/.hermes/.backups/unifi-sync" TS="$(date -u +%Y%m%d-%H%M%S)" LOG="/tmp/unifi-backup-sync-${TS}.log" # Cron-safe AWS CLI path if [ -f /opt/awscli-venv/bin/activate ]; then # shellcheck disable=SC1091 source /opt/awscli-venv/bin/activate fi log() { echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] $*" | tee -a "$LOG"; } cleanup() { rm -f "$LOG" rm -rf "$STAGE" } trap cleanup EXIT log "Starting UniFi backup sync from ${SOURCE_HOST}:${SOURCE_PATH}" # Pull backups via rsync mkdir -p "$STAGE" if ! rsync -az --timeout=30 \ -e "ssh -i ${SSH_KEY} -o ConnectTimeout=10 -o BatchMode=yes" \ "root@${SOURCE_HOST}:${SOURCE_PATH}/" \ "$STAGE/" >/dev/null 2>&1; then log "FATAL: rsync from ${SOURCE_HOST} failed — server unreachable or path missing" exit 1 fi COUNT=$(find "$STAGE" -name '*.unf' | wc -l) SIZE=$(du -sh "$STAGE" | cut -f1) log "Pulled ${COUNT} .unf files (${SIZE})" # Upload to S3 if aws s3 sync "$STAGE/" "$S3_BUCKET/" \ --endpoint-url "$ENDPOINT" \ --delete \ >>"$LOG" 2>&1; then log "Uploaded to ${S3_BUCKET}" else log "FATAL: S3 upload failed" exit 1 fi log "Sync complete: ${COUNT} files — s3://hermes-vps-backups/unifi-backups/"