Barazo Docker Compose templates for self-hosting barazo.forum
at main 115 lines 3.8 kB view raw
1#!/usr/bin/env bash 2# Barazo Restore Script 3# 4# Restores a PostgreSQL backup from a file created by backup.sh. 5# 6# Usage: 7# ./scripts/restore.sh backups/barazo-backup-20260214-020000.sql.gz 8# ./scripts/restore.sh backups/barazo-backup-20260214-020000.sql.gz.age 9# 10# For encrypted backups (.age), set BACKUP_PRIVATE_KEY_FILE to the path 11# of your age private key file. 12# 13# WARNING: This will overwrite the current database contents. 14 15set -euo pipefail 16 17COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.yml}" 18 19if [ $# -lt 1 ]; then 20 echo "Usage: $0 <backup-file>" >&2 21 echo "" >&2 22 echo "Examples:" >&2 23 echo " $0 backups/barazo-backup-20260214-020000.sql.gz" >&2 24 echo " $0 backups/barazo-backup-20260214-020000.sql.gz.age" >&2 25 echo "" >&2 26 echo "Environment variables:" >&2 27 echo " BACKUP_PRIVATE_KEY_FILE Path to age private key (for .age files)" >&2 28 echo " COMPOSE_FILE Docker Compose file (default: docker-compose.yml)" >&2 29 exit 1 30fi 31 32BACKUP_FILE="$1" 33 34if [ ! -f "$BACKUP_FILE" ]; then 35 echo "Error: Backup file not found: $BACKUP_FILE" >&2 36 exit 1 37fi 38 39# Check if encrypted 40IS_ENCRYPTED=false 41if [[ "$BACKUP_FILE" == *.age ]]; then 42 IS_ENCRYPTED=true 43 if [ -z "${BACKUP_PRIVATE_KEY_FILE:-}" ]; then 44 echo "Error: Encrypted backup requires BACKUP_PRIVATE_KEY_FILE environment variable" >&2 45 exit 1 46 fi 47 if [ ! -f "$BACKUP_PRIVATE_KEY_FILE" ]; then 48 echo "Error: Private key file not found: $BACKUP_PRIVATE_KEY_FILE" >&2 49 exit 1 50 fi 51 if ! command -v age &>/dev/null; then 52 echo "Error: age is required for decryption. Install: https://github.com/FiloSottile/age" >&2 53 exit 1 54 fi 55fi 56 57# Confirm 58echo "WARNING: This will overwrite the current database." 59echo "Backup file: $BACKUP_FILE" 60echo "" 61read -p "Continue? (y/N) " -r 62if [[ ! $REPLY =~ ^[Yy]$ ]]; then 63 echo "Restore cancelled." 64 exit 0 65fi 66 67# Check PostgreSQL is running 68if ! docker compose -f "$COMPOSE_FILE" exec -T postgres pg_isready -U "${POSTGRES_USER:-barazo}" &>/dev/null; then 69 echo "Error: PostgreSQL is not running. Start it with: docker compose -f $COMPOSE_FILE up -d postgres" >&2 70 exit 1 71fi 72 73echo "Starting restore at $(date)" 74 75# Stop API and Web to prevent writes during restore 76echo "Stopping API and Web services..." 77docker compose -f "$COMPOSE_FILE" stop barazo-api barazo-web 2>/dev/null || true 78 79# Restore 80DB_NAME="${POSTGRES_DB:-barazo}" 81DB_USER="${POSTGRES_USER:-barazo}" 82 83echo "Dropping and recreating database..." 84docker compose -f "$COMPOSE_FILE" exec -T postgres \ 85 psql -U "$DB_USER" -d postgres -c "DROP DATABASE IF EXISTS $DB_NAME;" 86docker compose -f "$COMPOSE_FILE" exec -T postgres \ 87 psql -U "$DB_USER" -d postgres -c "CREATE DATABASE $DB_NAME OWNER $DB_USER;" 88 89echo "Restoring from backup..." 90if [ "$IS_ENCRYPTED" = true ]; then 91 age -d -i "$BACKUP_PRIVATE_KEY_FILE" "$BACKUP_FILE" \ 92 | gunzip \ 93 | docker compose -f "$COMPOSE_FILE" exec -T postgres psql -U "$DB_USER" -d "$DB_NAME" -q 94else 95 gunzip -c "$BACKUP_FILE" \ 96 | docker compose -f "$COMPOSE_FILE" exec -T postgres psql -U "$DB_USER" -d "$DB_NAME" -q 97fi 98 99# Restart services 100echo "Restarting API and Web services..." 101docker compose -f "$COMPOSE_FILE" up -d barazo-api barazo-web 102 103# Verify 104echo "Verifying restore..." 105sleep 5 106TABLE_COUNT=$(docker compose -f "$COMPOSE_FILE" exec -T postgres \ 107 psql -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT count(*) FROM information_schema.tables WHERE table_schema = 'public';") 108echo "Tables in database: $(echo "$TABLE_COUNT" | tr -d ' ')" 109 110echo "" 111echo "Restore complete at $(date)" 112echo "" 113echo "IMPORTANT: If this backup is older than the latest data, check the" 114echo "deletion_log table and re-apply any deletions that occurred after" 115echo "the backup timestamp to maintain GDPR compliance."