Why backup is built-in
Multi-tenant gateways earn an enormous amount of trust from their tenants — sessions, memory, channel pairings, paid-for cost history. Lose any of it and the tenant churns. So OpenClawMU treats backup as a first-class primitive, not a "you should run pg_dump in cron" afterthought.
A tenant tarball captures everything reproducible — every directory
under tenants/<name>/ except for ephemeral pty
state. Restore on the same or a different gateway, with the same
or a different name, and the tenant resumes — same token, same
sessions, same memory, same channel pairings (you'll need to
re-pair WhatsApp by QR but Telegram/Slack tokens survive).
Backup
# To AWS S3
openclaw tenants backup acme \
--to s3://my-bucket/acme/2026-06-03.tar.zst \
--aws-profile production
# To MinIO / R2 / any S3-compatible
openclaw tenants backup acme \
--to s3://my-bucket/acme/2026-06-03.tar.zst \
--endpoint https://minio.internal:9000 \
--access-key $S3_AK --secret-key $S3_SK
# To local file (for ops sanity checks)
openclaw tenants backup acme \
--to /var/backups/openclawmu/acme/2026-06-03.tar.zst
# Encrypted (pipe through age before upload)
openclaw tenants backup acme \
--to s3://my-bucket/acme/2026-06-03.tar.zst.age \
--pipe "age -r age1abc..." Restore
# Restore on a fresh gateway (tenant slot must be empty)
openclaw tenants restore \
--from s3://my-bucket/acme/2026-06-03.tar.zst
# Restore with a new name (useful for staging clones)
openclaw tenants restore \
--from s3://my-bucket/acme/2026-06-03.tar.zst \
--as acme-staging
# Restore over an existing tenant (requires --force)
openclaw tenants restore \
--from s3://my-bucket/acme/2026-06-03.tar.zst \
--force Path-traversal hardening
Both endpoints sanitize the source / destination paths to prevent a malicious tarball from writing outside the tenant root, and to prevent a misconfigured CLI from reading a host file as a tenant source. Specifically:
- Tarball entries are restricted to the
tenants/<name>/...prefix. - Symlinks inside the tarball are dereferenced relative to the tenant root and rejected if they escape.
- Restore destination is always under the configured tenant base dir;
..in the--asname is rejected. - The S3 key is validated to contain no
..segments before being passed to the S3 client.
Automation
Schedule backups by tenant via the gateway's cron primitive — yes, the same cron primitive you give your tenants. Or run them from your own cron / Kubernetes CronJob.
# Schedule a nightly backup for one tenant
openclaw cron add acme \
--schedule "0 3 * * *" \
--name "nightly-backup" \
--cmd "openclaw tenants backup acme --to s3://my-bucket/acme/\$(date +%F).tar.zst"
# Or do all of them
for t in $(openclaw tenants list --names); do
openclaw tenants backup $t --to s3://my-bucket/$t/$(date +%F).tar.zst
done