#!/bin/bash # DocFast BorgBackup Script - Full Disaster Recovery # Backs up: PostgreSQL, Docker volumes, nginx config, SSL certs, crontabs, OpenDKIM keys # Schedule: daily at 03:00 UTC, keeps 7 daily + 4 weekly + 3 monthly set -euo pipefail # Configuration BORG_REPO="/opt/borg-backups/docfast" BACKUP_NAME="docfast-$(date +%Y-%m-%d_%H%M)" TEMP_DIR="/tmp/docfast-backup-$$" LOG_FILE="/var/log/docfast-backup.log" # Database configuration DB_NAME="docfast" DB_USER="docfast" DB_HOST="localhost" DB_PORT="5432" # Logging function log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE" } # Error handler error_exit() { log "ERROR: $1" cleanup exit 1 } # Cleanup function cleanup() { if [[ -d "$TEMP_DIR" ]]; then rm -rf "$TEMP_DIR" fi } # Trap cleanup on exit trap cleanup EXIT log "Starting DocFast backup: $BACKUP_NAME" # Create temporary directory mkdir -p "$TEMP_DIR" mkdir -p "$(dirname "$LOG_FILE")" # 1. PostgreSQL dump log "Creating PostgreSQL dump..." export PGPASSFILE="/root/.pgpass" pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \ --no-password --verbose --clean --if-exists --format=custom \ > "$TEMP_DIR/docfast-db.dump" 2>>"$LOG_FILE" || error_exit "PostgreSQL dump failed" # Verify dump is valid if ! pg_restore --list "$TEMP_DIR/docfast-db.dump" >/dev/null 2>&1; then error_exit "PostgreSQL dump verification failed" fi log "PostgreSQL dump completed: $(stat -c%s "$TEMP_DIR/docfast-db.dump") bytes" # 2. Docker volumes log "Backing up Docker volumes..." mkdir -p "$TEMP_DIR/docker-volumes" if [[ -d "/var/lib/docker/volumes" ]]; then cp -r /var/lib/docker/volumes/* "$TEMP_DIR/docker-volumes/" || error_exit "Docker volumes backup failed" log "Docker volumes backed up" else log "WARNING: No Docker volumes found" fi # 3. Nginx configuration log "Backing up nginx configuration..." mkdir -p "$TEMP_DIR/nginx" cp -r /etc/nginx/* "$TEMP_DIR/nginx/" || error_exit "Nginx backup failed" log "Nginx configuration backed up" # 4. SSL certificates log "Backing up SSL certificates..." mkdir -p "$TEMP_DIR/letsencrypt" cp -r /etc/letsencrypt/* "$TEMP_DIR/letsencrypt/" || error_exit "SSL certificates backup failed" log "SSL certificates backed up" # 5. Crontabs log "Backing up crontabs..." mkdir -p "$TEMP_DIR/crontabs" if [[ -d "/var/spool/cron/crontabs" ]]; then cp -r /var/spool/cron/crontabs/* "$TEMP_DIR/crontabs/" 2>/dev/null || log "No crontabs found" fi # Also backup user crontabs crontab -l > "$TEMP_DIR/crontabs/root-crontab.txt" 2>/dev/null || echo "# No root crontab" > "$TEMP_DIR/crontabs/root-crontab.txt" log "Crontabs backed up" # 6. OpenDKIM keys log "Backing up OpenDKIM keys..." mkdir -p "$TEMP_DIR/opendkim" cp -r /etc/opendkim/* "$TEMP_DIR/opendkim/" || error_exit "OpenDKIM backup failed" log "OpenDKIM keys backed up" # 7. DocFast application files (docker-compose, env, scripts) log "Backing up DocFast application files..." mkdir -p "$TEMP_DIR/docfast-app" if [[ -d "/opt/docfast" ]]; then 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 log "DocFast application files backed up" fi # 8. System information log "Creating system information backup..." mkdir -p "$TEMP_DIR/system" systemctl list-unit-files --state=enabled > "$TEMP_DIR/system/enabled-services.txt" dpkg -l > "$TEMP_DIR/system/installed-packages.txt" uname -a > "$TEMP_DIR/system/system-info.txt" df -h > "$TEMP_DIR/system/disk-usage.txt" log "System information backed up" # 9. Create Borg backup log "Creating Borg backup..." export BORG_PASSPHRASE="docfast-backup-$(date +%Y)" export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes # Initialize repository if it doesn't exist if [[ ! -d "$BORG_REPO" ]]; then log "Initializing new Borg repository..." borg init --encryption=repokey "$BORG_REPO" || error_exit "Failed to initialize Borg repository" fi # Create backup log "Creating Borg archive: $BACKUP_NAME" borg create \ --verbose \ --filter AME \ --list \ --stats \ --show-rc \ --compression lz4 \ --exclude-caches \ "$BORG_REPO::$BACKUP_NAME" \ "$TEMP_DIR" 2>>"$LOG_FILE" || error_exit "Borg backup creation failed" # 10. Prune old backups (7 daily, 4 weekly, 3 monthly) log "Pruning old backups..." borg prune \ --list \ --prefix 'docfast-' \ --show-rc \ --keep-daily 7 \ --keep-weekly 4 \ --keep-monthly 3 \ "$BORG_REPO" 2>>"$LOG_FILE" || error_exit "Borg pruning failed" # 11. Compact repository log "Compacting repository..." borg compact "$BORG_REPO" 2>>"$LOG_FILE" || log "WARNING: Repository compaction failed (non-fatal)" # 12. Repository info log "Backup completed successfully!" borg info "$BORG_REPO" 2>>"$LOG_FILE" log "DocFast backup completed: $BACKUP_NAME"