#!/usr/bin/env bash # restore.sh — Restore Cloud Elves services from a backup # # Usage: ./scripts/restore.sh # # Prerequisites: # - Target server already bootstrapped: ansible-playbook playbooks/bootstrap.yml # - Services already deployed: ansible-playbook playbooks/deploy.yml # - This script stops services, replaces data, and restarts # # Run from the ce-infra repo root directory. # Requires SSH access to box.cloud-elves.eu as root. set -euo pipefail if [ $# -eq 0 ]; then echo "Usage: $0 " echo "Example: $0 ./backups/ce-backup-20260317-180000.tar" exit 1 fi BACKUP_FILE="$1" HOST="root@box.cloud-elves.eu" SSH_KEY="${SSH_KEY:-$HOME/.ssh/id_ed25519_ce}" SSH="ssh -i $SSH_KEY $HOST" SCP="scp -i $SSH_KEY" REMOTE_TMP="/tmp/ce-restore" if [ ! -f "${BACKUP_FILE}" ]; then echo "Error: Backup file not found: ${BACKUP_FILE}" exit 1 fi echo "=== Cloud Elves Restore ===" echo "Backup: ${BACKUP_FILE}" echo "" echo "Contents:" tar tf "${BACKUP_FILE}" | sed 's/^/ /' echo "" echo "WARNING: This will stop all services and replace their data." echo "Press Enter to continue, Ctrl+C to abort." read -r # Upload backup echo "[1/7] Uploading backup to server..." $SSH "mkdir -p ${REMOTE_TMP}" $SCP "${BACKUP_FILE}" "${HOST}:${REMOTE_TMP}/backup.tar" $SSH "cd ${REMOTE_TMP} && tar xf backup.tar && rm backup.tar" # Stop all services echo "[2/7] Stopping all services..." $SSH "cd /opt/services && docker compose down" # Restore LLDAP volume echo "[3/7] Restoring LLDAP (user directory)..." $SSH "docker volume rm services_lldap-data 2>/dev/null || true && docker volume create services_lldap-data" $SSH "docker run --rm -v services_lldap-data:/data -v ${REMOTE_TMP}:/backup alpine tar xzf /backup/lldap-data.tar.gz -C /data" # Restore Dex volume echo "[4/7] Restoring Dex (auth database)..." $SSH "docker volume rm services_dex-data 2>/dev/null || true && docker volume create services_dex-data" $SSH "docker run --rm -v services_dex-data:/dex -v ${REMOTE_TMP}:/backup alpine tar xzf /backup/dex-data.tar.gz -C /dex" # Restore Gitea data volume echo "[5/7] Restoring Gitea (data + database)..." $SSH "docker volume rm services_gitea-data 2>/dev/null || true && docker volume create services_gitea-data" $SSH "docker run --rm -v services_gitea-data:/data -v ${REMOTE_TMP}:/backup alpine tar xzf /backup/gitea-data.tar.gz -C /data" # Start databases only so we can restore into them $SSH "cd /opt/services && docker compose up -d gitea-db outline-db" echo " Waiting for databases to start..." sleep 5 # Restore Gitea database $SSH "cd /opt/services && docker compose exec -T gitea-db dropdb -U gitea --if-exists gitea" $SSH "cd /opt/services && docker compose exec -T gitea-db createdb -U gitea gitea" $SSH "gunzip -c ${REMOTE_TMP}/gitea-db.sql.gz | docker compose -f /opt/services/docker-compose.yml exec -T gitea-db psql -U gitea gitea" # Restore Outline data volume echo "[6/7] Restoring Outline (uploads + database)..." $SSH "docker volume rm services_outline-data 2>/dev/null || true && docker volume create services_outline-data" $SSH "docker run --rm -v services_outline-data:/data -v ${REMOTE_TMP}:/backup alpine tar xzf /backup/outline-data.tar.gz -C /data" # Restore Outline database $SSH "cd /opt/services && docker compose exec -T outline-db dropdb -U outline --if-exists outline" $SSH "cd /opt/services && docker compose exec -T outline-db createdb -U outline outline" $SSH "gunzip -c ${REMOTE_TMP}/outline-db.sql.gz | docker compose -f /opt/services/docker-compose.yml exec -T outline-db psql -U outline outline" # Start everything echo "[7/7] Starting all services..." $SSH "cd /opt/services && docker compose up -d" # Wait for Gitea and regenerate hooks echo " Waiting for services to start..." sleep 10 echo " Regenerating Gitea hooks..." $SSH "cd /opt/services && docker compose exec -T -u git gitea gitea admin regenerate hooks" || echo " (no repos to regenerate hooks for)" # Clean up $SSH "rm -rf ${REMOTE_TMP}" echo "" echo "=== Restore complete ===" echo "" echo "Please verify:" echo " - https://ldap.cloud-elves.eu — LLDAP (users should be there)" echo " - https://auth.cloud-elves.eu — Dex (SSO should work)" echo " - https://git.cloud-elves.eu — Gitea (repos, users)" echo " - https://docs.cloud-elves.eu — Outline (documents)" echo " - https://cloud-elves.eu — Static site (deploy via rsync separately)" echo "" echo "Note: Users will need to log in again (SSO sessions were reset)."