storage.json, oracle.db (copied through SQLite’s online backup
API, so the file is consistent even if a crash left an uncheckpointed
WAL), and blobs/ — plus a manifest.json with sha256 checksums.
Config (daemon.json) and logs are not state and stay out of the
snapshot.
--force, and replaces state wholesale: stale WAL
sidecars and leftover blobs are dropped. A restore is a rewind, not
a merge.
What the guardrails look like
ohd backupinto a non-empty directory refuses:destination <dir> already exists and is not empty — back up into a fresh directory.- A directory without a manifest is rejected:
<dir> is not a backup — no manifest.json (torn backup or wrong directory). - A file that fails its checksum stops the restore before anything is
touched:
snapshot is corrupt — <path> does not match its manifest checksum. - A never-booted data dir has nothing to snapshot:
nothing to back up — <data dir> holds no storage.json or oracle.db (never booted?).
What to back up besides
The snapshot is the daemon’s state. For a full disaster-recovery picture, also keep copies of:daemon.json— your durable configuration (bind posture, hosts, OIDC provider).- Your reverse-proxy config and certificates, if you run TLS termination.