Backup & Restore

KubeClaw can back up the Gateway state directory to any S3-compatible storage (AWS S3, MinIO, Backblaze B2, Cloudflare R2) on a cron schedule. A pre-delete hook also runs a final backup before helm uninstall, so state is preserved even when tearing down the release.

Backups use rclone to copy the flat Markdown files. No database dump or special tooling is needed.

What gets backed up

  • Primary PVC: /home/node/.openclaw (excluding workspace if split)
  • Workspace PVC: /home/node/.openclaw/workspace (if split volumes are enabled)

Enable S3 backups

Add S3 credentials to secret.data and enable the backup:

yaml
secret:
  create: true
  data:
    OPENCLAW_GATEWAY_TOKEN: "your-token"
    S3_ENDPOINT: "https://s3.us-east-1.amazonaws.com"
    S3_BUCKET: "my-kubeclaw-backups"
    S3_ACCESS_KEY_ID: "AKIAEXAMPLE"
    S3_SECRET_ACCESS_KEY: "your-secret-key"
    S3_REGION: "us-east-1"
yaml
backup:
  enabled: true
  schedule: "0 2 * * *"   # daily at 2am UTC

The chart validates that S3_BUCKET, S3_ACCESS_KEY_ID, and S3_SECRET_ACCESS_KEY are present in secret.data when backup.enabled is true.

S3 path layout

Scheduled backups are timestamped. The pre-delete backup overwrites a single pre-delete/ prefix so only the latest snapshot is kept:

s3://my-kubeclaw-backups/
  <namespace>/<release>/
    2026-03-07T02-00-00Z/       # scheduled
    2026-03-08T02-00-00Z/       # scheduled
    pre-delete/                  # latest pre-delete snapshot

Override the <namespace>/<release> prefix with backup.pathPrefix.

Non-AWS providers

Any S3-compatible endpoint works. Set S3_ENDPOINT to your provider's URL:

ProviderS3_ENDPOINT example
MinIOhttp://minio.minio.svc:9000
Backblaze B2https://s3.us-west-004.backblazeb2.com
Cloudflare R2https://<account-id>.r2.cloudflarestorage.com

Disable the pre-delete hook

If you do not want a backup on helm uninstall:

yaml
backup:
  enabled: true
  onDelete:
    enabled: false

Restore methods

Three restore methods are supported depending on your backup strategy.

Method 1: CSI VolumeSnapshot

Requires a CSI snapshot controller, VolumeSnapshot and VolumeSnapshotClass CRDs, and an existing snapshot.

Identify the snapshot:

shell
kubectl -n <namespace> get volumesnapshots

Scale down the Gateway:

shell
kubectl -n <namespace> scale statefulset/openclaw-gateway --replicas=0

Delete the existing PVC (verify the snapshot is READYTOUSE: true first):

shell
kubectl -n <namespace> delete pvc state-openclaw-gateway-0

Create a new PVC from the snapshot:

yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: state-openclaw-gateway-0
  namespace: <namespace>
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: <your-storage-class>
  resources:
    requests:
      storage: <size-matching-original>
  dataSource:
    name: <snapshot-name>
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io

Scale the Gateway back up:

shell
kubectl -n <namespace> scale statefulset/openclaw-gateway --replicas=1

Method 2: Manual tarball

Create a backup from the running Gateway:

shell
kubectl -n <namespace> exec statefulset/<release-name> -- \
  tar czf - /home/node/.openclaw \
  > ./openclaw-backup/openclaw-state-$(date +%Y%m%d%H%M%S).tar.gz

Restore by scaling down the Gateway, running a temporary busybox pod with the PVC mounted, copying the tarball in, extracting, then scaling back up. See the full restore runbook for step-by-step instructions.

Method 3: Restore from S3

If the chart's S3 backup feature (backup.enabled: true) is configured, use rclone to pull the backup into the PVC.

List available backups:

shell
rclone lsd s3:<bucket>/<namespace>/<release>/

Restore by scaling down the Gateway, running a temporary rclone pod with the PVC mounted, pulling the backup with rclone copy, then scaling back up. See the full restore runbook for detailed commands.


Post-restore checklist

  • Gateway pods are Running and Ready (readiness probe passes)
  • openclaw doctor reports no critical issues
  • openclaw status shows expected gateway state
  • Control UI is accessible and authenticated
  • No unexpected PVC size changes (kubectl get pvc)

Troubleshooting

Gateway fails to start after restore: run doctor to repair config issues.

shell
kubectl -n <namespace> exec statefulset/<release-name> -- \
  node dist/index.js doctor --yes

Config is invalid after restore: delete the config file and let the Gateway regenerate defaults.

shell
kubectl -n <namespace> exec statefulset/<release-name> -- \
  rm /home/node/.openclaw/openclaw.json
shell
kubectl -n <namespace> rollout restart statefulset/<release-name>