#!/usr/bin/env bash # backup.sh — Create a full backup of all Cloud Elves services # # Usage: ./scripts/backup.sh [destination_dir] # # Creates a timestamped tarball containing volume-level backups of all services. # Run from the ce-infra repo root directory. # Requires SSH access to box.cloud-elves.eu as root. set -euo pipefail 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" TIMESTAMP=$(date +%Y%m%d-%H%M%S) DEST_DIR="${1:-./backups}" BACKUP_NAME="ce-backup-${TIMESTAMP}" REMOTE_TMP="/tmp/${BACKUP_NAME}" echo "=== Cloud Elves Backup — ${TIMESTAMP} ===" echo "" # Create local destination mkdir -p "${DEST_DIR}" # Create remote temp directory echo "[1/7] Preparing..." $SSH "mkdir -p ${REMOTE_TMP}" # Stop services for consistent backup (databases stay up for pg_dump) echo "[2/7] Stopping application services for consistent backup..." $SSH "cd /opt/services && docker compose stop gitea outline dex lldap gitea-runner caddy" # Gitea: pg_dump + data volume echo "[3/7] Backing up Gitea (database + data)..." $SSH "cd /opt/services && docker compose exec -T gitea-db pg_dump -U gitea gitea | gzip > ${REMOTE_TMP}/gitea-db.sql.gz" $SSH "docker run --rm -v services_gitea-data:/data -v ${REMOTE_TMP}:/backup alpine tar czf /backup/gitea-data.tar.gz -C /data ." # Outline: pg_dump + data volume echo "[4/7] Backing up Outline (database + uploads)..." $SSH "cd /opt/services && docker compose exec -T outline-db pg_dump -U outline outline | gzip > ${REMOTE_TMP}/outline-db.sql.gz" $SSH "docker run --rm -v services_outline-data:/data -v ${REMOTE_TMP}:/backup alpine tar czf /backup/outline-data.tar.gz -C /data ." # LLDAP: SQLite volume echo "[5/7] Backing up LLDAP (user directory)..." $SSH "docker run --rm -v services_lldap-data:/data -v ${REMOTE_TMP}:/backup alpine tar czf /backup/lldap-data.tar.gz -C /data ." # Dex: SQLite volume echo "[6/7] Backing up Dex (auth database)..." $SSH "docker run --rm -v services_dex-data:/dex -v ${REMOTE_TMP}:/backup alpine tar czf /backup/dex-data.tar.gz -C /dex ." # Restart services echo "[7/7] Restarting services..." $SSH "cd /opt/services && docker compose up -d" # Bundle everything and download echo "" echo "Downloading backup..." $SSH "cd /tmp && tar cf ${BACKUP_NAME}.tar -C ${REMOTE_TMP} ." $SCP "${HOST}:/tmp/${BACKUP_NAME}.tar" "${DEST_DIR}/${BACKUP_NAME}.tar" # Clean up remote $SSH "rm -rf ${REMOTE_TMP} /tmp/${BACKUP_NAME}.tar" # Show result BACKUP_SIZE=$(du -h "${DEST_DIR}/${BACKUP_NAME}.tar" | cut -f1) echo "" echo "=== Backup complete ===" echo "File: ${DEST_DIR}/${BACKUP_NAME}.tar (${BACKUP_SIZE})" echo "" echo "Contents:" tar tf "${DEST_DIR}/${BACKUP_NAME}.tar" | sed 's/^/ /' echo "" echo "Downtime was ~30 seconds while services were stopped for consistency."