- scripts/borg-backup.sh: Complete disaster recovery backup (PostgreSQL, Docker volumes, configs, SSL certs, DKIM keys) - scripts/borg-restore.sh: Automated restore from Borg backups with manual verification steps - scripts/rollback.sh: Quick application rollback using Docker image tags - Enhanced setup.sh with BorgBackup installation and cron job setup - Updated README with detailed backup strategy documentation (2-tier: SQLite + Borg) Backup retention: 7 daily + 4 weekly + 3 monthly Borg archives + 7 days SQLite snapshots
162 lines
No EOL
4.9 KiB
Bash
Executable file
162 lines
No EOL
4.9 KiB
Bash
Executable file
#!/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" |