OBLETHdocs

Backup and restore

Copy a gateway's configuration to a file and restore it, and back up the datastores for full disaster recovery.

4 min readUpdated for v2.4.0Edit on GitHub

Config backupSettings › Data and backups
It holdsModels, tenants, keys, MCP servers, settings
Restore needsThe same OBLETH_ENCRYPTION_KEY
Full recoveryBack up Postgres and ClickHouse too

A config backup is one JSON file with the gateway's configuration. Use it to clone an instance, move staging to production, or recover settings. It holds no usage history; for that, and for everything a config backup leaves out, back up the datastores.

Download a backup

In Settings › Data and backups, select Download backup. The file is named obleth-backup-<timestamp>.json. Or use the API:

curl -H "Authorization: Bearer $OBLETH_ADMIN_TOKEN" \
  http://localhost:9180/api/v1/backup/export \
  -o obleth-backup-$(date +%Y%m%d-%H%M%S).json

Restore a backup

  1. 1

    Choose the file

    In Settings › Data and backups, select Restore from backup… and pick the file. The dialog shows when it was taken, by which gateway version, and how many of each thing it holds.

  2. 2

    Confirm

    Tick the checkbox, type RESTORE, and select Restore backup.

  3. 3

    Read the report

    It lists how many of each were added and updated, and any warnings.

Through the API, post the file to POST /api/v1/backup/restore; the response is the same report as JSON, with inserted and updated counts per section and a warnings list.

Restore is a merge: everything in the file is created or updated by id, and nothing that exists only on the target is deleted. It is applied in one transaction, all or nothing. Afterwards the gateway rebuilds its Redis caches and reloads alert settings, so the data plane serves the restored configuration at once. Existing client keys keep working, because their hashes are in the file. Both export and restore are recorded in the audit log, with counts but never the payload.

What a backup contains

SectionContents
fairshare_groupsName and weight
tenantsProfile, group and weight, token rate, in-flight cap, status, time zone, access window and weekly hours, budget, model allowlist
api_keysPrefix and hash, kind and identity fields, budget, weight, in-flight cap, per-user fairshare, disabled flag
modelsThe whole route: names and aliases, upstream and api_base, key and upstream headers, type, prices, context window, capacity (including discovered-capacity settings), capabilities, cache, tags, boons, tool servers, routing, speculation, timeouts and retries, endpoint selection, health-check settings
model_endpointsName, api_base, key, priority, weight, enabled flag
mcp_serversName, URL, auth header, enabled flag
app_settingsEvery settings row: alerts, routing, boons, energy, Slurm, assistant, retention, and the dashboard's own key

Each model carries its variants and lifecycle status; a model in a backup taken before v2.1.0 restores as active.

Not included: the audit log and all of ClickHouse; model health history and state; knowledge collections and documents; recipes, Slurm deployments and replicas; video job records; tenant guardrails and compression policies; the synthetic flag and tracing flags. Recreate those on the target, or restore the datastores instead.

Back up the datastores

DatastoreHoldsBack it up with
PostgresAll configuration, keys, tenants, knowledge, the audit log, the dashboard's accountspg_dump, or continuous WAL archiving (CloudNativePG, pgBackRest, Barman) for point-in-time recovery
RedisCaches rebuilt from Postgres; per-minute buckets, term-budget usage, the response cacheAOF persistence (on in the bundled Redis)
ClickHouseThe usage ledgerYour provider's backups, or clickhouse-backup
pg_dump -h $PGHOST -U obleth -d obleth -F c -f obleth-$(date +%Y%m%d).dump
pg_restore -h $PGHOST -U obleth -d obleth obleth-20260101.dump

After restoring Postgres or Redis, run Reconcile cache… in Settings › Data and backups, or POST /api/v1/resync, so Redis matches Postgres. Without it, the next rewarm (OBLETH_REDIS_REWARM_SECS, 300 s) gets there.

Retention is the gateway's job, not ClickHouse's: it drops raw usage days older than OBLETH_USAGE_RETENTION_DAYS (180, or Keep request history for in Settings › Data and backups) and never prunes the usage_daily rollup. Don't add your own TTL to usage.

What you lose without one

LostResultRecovery
RedisCaches empty; per-minute buckets, term-budget usage and the response cache resetAutomatic within one rewarm, or at once with a resync
Postgres, with a config backupKnowledge, recipes, Slurm deployments and the other exclusions aboveRestore the config backup, then recreate the rest
Postgres, no backupEvery tenant, key and modelNone
ClickHouse, no backupUsage history and billing dataOnly rows still in gateway spill files replay
A gateway podIts unreplayed spill file, which is per podNone
Checks before a restore writes anything

Three checks run first, and any failure rejects the whole restore:

  1. Format and version. The file must be an obleth config backup of a version this gateway reads.
  2. Encryption key. The file carries a key_check value encrypted with the exporter's key. A different key, or no key on the target for an encrypted backup, is refused with 400. Two instances without keys restore in plaintext; an unencrypted backup restored onto an instance with a key is encrypted on write.
  3. Destination policy. Every outbound URL the restore would register (model and endpoint api_base, verify URLs, MCP URLs, and the URLs inside settings such as the Slack webhook) is checked against the same policy as the create forms. See Security.

A pepper mismatch cannot be detected from the hashes. The file records whether the exporter used OBLETH_API_KEY_PEPPER; if that differs from the target, the restore applies and warns that restored keys won't authenticate until the peppers match.