#!/usr/bin/env bash # ============================================================================== # OpenClaw Backup Script # ============================================================================== # Works for both local and Docker deployments. # # Usage: backup-openclaw.sh # backup-openclaw.sh --cold # ============================================================================== set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "${SCRIPT_DIR}/common.sh" parse_args "$@" SERVICE_NAME="openclaw" BASE_DIR="/opt/${SERVICE_NAME}" CONFIG_NAME="${SERVICE_NAME}" BACKUP_DIR="/opt/backup" STAMP="$(date +%Y%m%d-%H%M%S)" BACKUP_FILE="${BACKUP_DIR}/backup-${SERVICE_NAME}-${STAMP}.tar.gz" [[ -d "$BASE_DIR" ]] || fatal "OpenClaw is not deployed at ${BASE_DIR}." mkdir -p "$BACKUP_DIR" # --- Cold backup: stop service --- if [[ "$ARG_COLD" == "1" ]]; then info "Running cold backup (stopping service)..." if [[ -f "${BASE_DIR}/docker-compose.yml" ]]; then (cd "$BASE_DIR" && docker compose down) elif systemctl is-active --quiet "${SERVICE_NAME}.service" 2>/dev/null; then systemctl stop "${SERVICE_NAME}.service" fi fi # --- Create archive --- info "Creating archive..." tar_paths=("opt/${SERVICE_NAME}") if [[ -f "${TRAEFIK_DYNAMIC_DIR}/${CONFIG_NAME}.yml" ]]; then tar_paths+=("opt/traefik/dynamic/${CONFIG_NAME}.yml") fi tar czf "$BACKUP_FILE" -C / "${tar_paths[@]}" # --- Cold: restart --- if [[ "$ARG_COLD" == "1" ]]; then if [[ -f "${BASE_DIR}/docker-compose.yml" ]]; then (cd "$BASE_DIR" && docker compose up -d) elif [[ -f "/etc/systemd/system/${SERVICE_NAME}.service" ]]; then systemctl start "${SERVICE_NAME}.service" fi ok "Service restarted." fi # --- Rotate old backups (keep last 5) --- # shellcheck disable=SC2012 ls -t "${BACKUP_DIR}/backup-${SERVICE_NAME}-"*.tar.gz 2>/dev/null | tail -n +6 | xargs -r rm -- ok "Backup: ${BACKUP_FILE} ($(du -h "$BACKUP_FILE" | cut -f1))"