#!/usr/bin/env bash # Restores an archive produced by backup-server.sh. Existing server state requires --force. set -euo pipefail root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) archive=${1:-} force=${2:-} project=${PROJECT_NAME:-eternitymail} staging=$(mktemp -d) cleanup() { rm -rf "$staging"; } trap cleanup EXIT [[ -n "$archive" && -f "$archive" ]] || { echo "Usage: $0 /path/to/backup.tar.gz [--force]" >&2; exit 1; } [[ "$force" == "--force" || ! -e "$root/.env" ]] || { echo "Refusing to overwrite an existing deployment without --force." >&2; exit 1; } tar -C "$staging" -xzf "$archive" (cd "$staging" && sha256sum -c SHA256SUMS) if [[ "$force" == "--force" ]]; then docker compose -f "$root/docker-compose.yml" --env-file "$root/.env" down || true docker volume rm "${project}-stalwart-etc" "${project}-stalwart-data" "${project}-stalwart-certs" 2>/dev/null || true rm -rf /opt/eternitymail/roundcube-db /opt/eternitymail/roundcube-config fi cp "$staging/.env" "$root/.env" project=$(sed -n 's/^PROJECT_NAME=//p' "$root/.env" | head -n1) project=${project:-eternitymail} for volume in stalwart-etc stalwart-data stalwart-certs; do docker volume create "${project}-${volume}" >/dev/null docker run --rm -v "${project}-${volume}:/destination" -v "$staging:/backup:ro" alpine:3.21 \ tar -C /destination -xzf "/backup/volumes/${volume}.tar.gz" done for directory in roundcube-db roundcube-config; do mkdir -p "/opt/eternitymail/${directory}" docker run --rm -v "/opt/eternitymail/${directory}:/destination" -v "$staging:/backup:ro" alpine:3.21 \ tar -C /destination -xzf "/backup/bind-mounts/${directory}.tar.gz" done docker compose -f "$root/docker-compose.yml" --env-file "$root/.env" up -d echo "Restore complete. Verify with: docker compose ps"