Backups
The Backups page configures automated and on-demand backups of the database cluster. The two toggles, times, and retentions are labelled "Config DB" and "Results DB" — a legacy naming from before the schemas shared one TimescaleDB cluster. They are NOT independent today: a backup runs (producing a FULL cluster bundle) at BOTH scheduled times whenever EITHER toggle is enabled, and the effective retention is the LONGER of the two values. Backups are encrypted at rest ONLY when an encryption key is configured (the default is no key → bundles are stored UNENCRYPTED); they can optionally be replicated to S3-compatible storage.
Inputs
| Name | Description | Allowed values | Default |
|---|---|---|---|
Config DB Enabled | Enable toggle (legacy "Config DB" label). Automated backups run at BOTH scheduled times whenever EITHER this or "Results DB Enabled" is on — they are an OR gate, not separate on/off switches | Boolean | true |
Config DB Schedule | Hour of day (UTC) for the first daily full-cluster backup (both times always run when backups are enabled) | 0-23 | 02:00 |
Results DB Enabled | Enable toggle (legacy "Results DB" label). See "Config DB Enabled" — either toggle on enables backups at both times | Boolean | true |
Results DB Schedule | Hour of day (UTC) for the second daily full-cluster backup | 0-23 | 03:00 |
Config DB Retention | Retention input (legacy label). The retention APPLIED to bundles is the LONGER of this and "Results DB Retention" | 1-365 days | 30 |
Results DB Retention | Retention input (legacy label). The retention APPLIED to bundles is the LONGER of this and "Config DB Retention" | 1-365 days | 7 |
Minimum Free Space | Backups are skipped if free disk space falls below this threshold | Bytes (positive integer) | 500 MB |
Encryption Key | Passphrase used to derive an AES-256 key for backup bundle encryption. Use a high-entropy value (generate one with the Generate Key button). Store the key securely outside mipo — without it, encrypted backups cannot be restored. | Any string or empty to disable | Empty (disabled) |
S3 Bucket | S3-compatible bucket for off-site backup replication | Valid bucket name | Empty (disabled) |
Fields & columns
| Name | Description |
|---|---|
Bundle | Unique identifier for the backup bundle |
Timestamp | When the backup was created |
Config DB | Bundle size attributed to the config schedule (legacy field; the bundle is one cluster dump) |
Results DB | Bundle size attributed to the results schedule (legacy field; the bundle is one cluster dump) |
How to
Trigger an immediate backup
- Click the "Backup Now" button in the Actions section
- Wait up to 60 seconds for the backup container to process the request
- Check the Trigger History section for the result status
Configure S3 replication
- Enable S3 and fill in the bucket, region, access key, and secret key
- Click "Test Connection" to verify S3 access
- Click "Save Configuration" to persist the settings
Restore from a backup
- There is no restore action on this page — Admin > Backups is trigger/config/history only.
- On a running deployment (including production), restore via the operator CLI: from the deployment dir run `scripts/ops/restore.sh <bundle>` (it connects as the cluster owner, stops the app containers, and rewrites the entire cluster — config, jobs, and results schemas).
- On a fresh host before an owner exists, the Day-0 Setup Wizard offers a restore path — but only where the manager has owner DB access (dev / a host with OWNER_DATABASE_URL); the standard prod manager does not, so prod uses the CLI.
Gotchas
- The backup container polls every 60 seconds, so triggered backups are not instantaneous.
- Backups are skipped automatically when free disk space is below the configured minimum.
- S3 endpoint is only needed for non-AWS S3-compatible providers (e.g., MinIO, Backblaze B2).
- Restore is available via the Day 0 Setup Wizard (GUI upload or S3 pull) or the CLI script (scripts/ops/restore.sh). Restore endpoints at /api/setup/restore/* are only accessible before an owner exists.
- The two retention values are NOT applied separately — every bundle is a full cluster snapshot, so the retention actually enforced is the LONGER of the "Config DB" and "Results DB" values (default: 30 days, the max of 30 and 7). Set the value you actually want as the larger of the two.
- There is no key escrow — losing the encryption key makes encrypted backups permanently unrecoverable. Store the key in a secure vault separate from the backup storage.
- Take a fresh backup before an in-place upgrade. The `mipo.sh deploy` preflight reports the newest backup age as an informational line but does NOT block the upgrade on it (owner decision 2026-07-08: backup freshness is a deployer judgment call). The other preflight checks — schema drift, disk free, scanner protocol, downgrade — remain fail-closed. See Admin > Release for the upgrade-readiness view and `docs/operations/upgrade.md` for the runbook.
API calls (8)
| Method | Path | Description |
|---|---|---|
| GET | /api/admin/backups/config | Retrieve current backup configuration |
| PUT | /api/admin/backups/config | Update backup configuration |
| GET | /api/admin/backups | List existing backup bundles |
| POST | /api/admin/backups/trigger | Trigger an immediate backup |
| GET | /api/admin/backups/triggers | List backup trigger history |
| POST | /api/admin/backups/test-s3 | Test S3 connection with current settings |
| GET | /api/admin/backups/:id/download | Download a backup bundle |
| POST | /api/admin/backups/generate-encryption-key | Generate a new backup encryption key (server-side crypto) |
Related
- Backup Health — Shows real-time backup process status and last run result
- Settings — System-wide settings that affect backup behavior
- Maintenance — Quick-access backup trigger and S3 test without leaving the maintenance page
- Release — Release shows the last backup timestamp alongside the rest of the upgrade-readiness posture.