Back up and restore

What to back up for each store (SQLite, MongoDB, FerretDB/PostgreSQL, runner files) and how to restore safely.

Back up two things: the store (database or files) and the secrets (database passwords, the runner’s master password and token). A runner backup without its master password is useless: the saved connections are encrypted with it.

By store

StoreHow
SQLite (single node)snapshot the volume, or sqlite3 oxysdb-server.sqlite ".backup …" while it runs (WAL mode)
MongoDBmongodump of oxysdb_server and oxysdb_runner, or the operator’s backups
FerretDBback up PostgreSQL (for CloudNativePG: its Barman Cloud backups and point-in-time recovery, configured through global.database.ferretdb.postgresql.cnpg.extraSpec)
Runner, file modeits data directory

docker compose

single, a consistent copy while running:

docker run --rm -v oxysdb-single_server-data:/data:ro -v "$PWD":/backup alpine \
  sh -c 'apk add -q sqlite && sqlite3 /data/oxysdb-server.sqlite ".backup /backup/oxysdb-server.sqlite"'

(or stop the server, copy the file, start it).

ha-mongodb:

docker compose -f compose.ha-mongodb.yaml exec -T mongo-1 sh -c \
  'mongodump --quiet --archive --gzip -u root -p "$(cat /run/secrets/mongo_root_password)" --authenticationDatabase admin \
   --db oxysdb_server' > oxysdb_server.archive.gz

and the same with --db oxysdb_runner.

ha-ferretdb:

docker compose -f compose.ha-ferretdb.yaml exec -T postgres pg_dump -U oxysdb -Fc postgres > oxysdb.pgdump

Always back up the secrets/ directory separately and safely.

Kubernetes

  • Back up the generated Secrets (kubectl get secret -l app.kubernetes.io/instance=<release>), or keep your own in a secret manager and pass them as existingSecret. An upgrade that finds a store without its credentials stops rather than locking the members out; the fix is restoring the Secret.
  • The data itself: the operator’s or CloudNativePG’s backups, or a mongodump.

Restoring a runner database

Database-mode runners remember the newest state they have seen (a manifest-counter file in each pod’s volume) and refuse an older one, so a restored backup is first refused with The runner database was rolled back. If the restore was intended:

  1. Check the tasks (runner.tasks from the desktop).
  2. Run oxysdb-runner reseal once, with the same database URL and master password as the runners. Pass --counter-floor N with the highest manifest-counter of runner replicas that are down but whose volume is kept, or they keep refusing the database when they return.

If the manifest fails its integrity check (The manifest fails the integrity check), reseal refuses to touch it; oxysdb-runner reseal --rebuild rebuilds it from the documents signed with the master password and prints every task and connection it keeps. Deleted tasks can come back: compare the list with what you expect and delete or send again what is wrong. SECURITY.md › Runner database recovery in the repository describes both cases in detail.

Tips

  • Test a restore regularly in a separate namespace or compose project.
  • Shared connections whose password was copied are stored on the server without application-level encryption: protect the server’s backups as you protect the database itself.