Octarq ships a built-in backup and restore subcommand for the database.
Read the warnings below before relying on them in production.
Two facts that shape every backup
1. Back up the whole data directory — a database backup alone is not enough
When Octarq boots with no configuration (the zero-config docker run path), it
generates a secret key and an initial admin password and persists them next to
the database, as octarq.secret and octarq-admin-password.txt (in the Docker
image: /data/octarq.secret and /data/octarq-admin-password.txt).
octarq.secretis the only thing that can decrypt stored credentials (TOTP seeds, plugin and provider secrets) — it is the key-encryption key.octarq-admin-password.txtis the only copy of the initial admin login.
Restoring only the database file on a different machine therefore leaves that
machine unable to decrypt any stored credential and without a working admin
login. Back up and restore the whole data directory — the database and the
two key files together. If you manage OCTARQ_SECRET_KEY / OCTARQ_ADMIN_PASSWORD
yourself via the environment, the equivalent of the key files lives in your
secret manager instead and must be backed up there.
2. Postgres backup/restore needs host tools — it cannot run inside the container
The Postgres path shells out to pg_dump / pg_restore / psql from the
PostgreSQL client tools (server/internal/db/backup.go).
The published Octarq images (scratch / distroless) are minimal and do not
contain those binaries, so octarq backup / octarq restore against Postgres
fail inside a stock container with a “pg_dump command not found” error. Run the
command on a host (or sidecar) that has postgresql-client installed and can
reach the Postgres server. SQLite has no such dependency — it is a pure-Go
VACUUM INTO snapshot.
Taking a backup
octarq backup [-o <output-path>]| Driver | Mechanism | While the server runs? |
|---|---|---|
sqlite |
Online, non-locking consistent snapshot via VACUUM INTO |
✅ safe |
postgres |
Plain pg_dump SQL dump |
✅ safe (needs pg_dump on the host, see above) |
Default output filename is octarq-backup-<timestamp>.db (SQLite) or
octarq-backup-<timestamp>.sql (Postgres) in the current directory; override
with -o / --out.
Restoring
octarq restore --in <backup-file> [-y | --yes]- The command refuses to proceed until you type
yes(or pass-y/--yes/--confirm). - Before restoring, it automatically creates a safety backup of the current
database (
octarq-backup-before-restore-<timestamp>.db) — a bad restore is never irreversible. - SQLite: the input file is integrity-checked (
PRAGMA integrity_check) before it replaces the live database, then swapped in atomically. If the Octarq server is running, restart it afterwards so it reloads the restored database. - Postgres: restores either a
pg_restorebinary dump (.dump/.tar) or a plain SQL dump viapsql, both with--cleansemantics on the target. As above, these two tools must exist on the host that runs the command.
Scheduling
backup is on-demand only — there is no built-in scheduler and nothing runs on
a timer. Backups happen when you make them happen: wire octarq backup (plus
the key files, §1) into your cron, Kubernetes CronJob, or backup agent, and test
a restore before you need one. The pre-launch checklist treats
this as a checklist item for a reason.
When the key and the data disagree
Every stored credential is ciphertext under the key from §1. Two situations leave that ciphertext unreadable:
- You restore a database without its key, or with a key from another install. The values decrypt with the old key only.
- You start the service on a fresh database that received the old rows but not
the old
settingstable.
Octarq stops the start when the database still holds encrypted values but the key that decrypts them is missing. A new key would make every saved value unreadable without a word. The error names the values to check: notification channels, webhook secrets, two-factor authentication, and OAuth client secrets.
To recover, restore the database and the key files together (§1), then start the service again. If you have no matching backup, delete the affected values and enter them again. The service encrypts the new values with the current key.