Backup and restore
A UniDPP deployment’s state is a small set of append-only files. This page
documents what they are, the consistency model that makes copying them safe
while services run, and the unidpp-ops backup/unidpp-ops restore tooling
contract.
Status of the tooling. The
unidpp-opsbackup/restore commands are implemented by theunidpp-opsprogram (built fromops-tools/in unidpp-pilot-data). The manualtar+shasumprocedure below is kept as the transparent form of the same contract; read it to understand what the program does. Everything below about the state layout and the consistency contract is verified against the running deployment; the exact command surface (unidpp-ops backup <tenant>,unidpp-ops restore <archive> <tenant>, the console Backups page) is the contract the tool implements.
What constitutes a deployment’s state
Section titled “What constitutes a deployment’s state”| File | Owner | Restores |
|---|---|---|
unidpp-operator.yaml |
the operator | the deployment declaration itself |
registry-journal.jsonl |
registry | every item, version, binding, discovery record |
trust-journal.jsonl |
trust | the trust graph, lists, revocations |
log-journal.jsonl |
log | the sequenced commitments and tree |
issuer-journal.jsonl |
issuer | every passport, event, pack record |
archive-journal.jsonl |
archive | every snapshot’s notarized record |
archive-snapshots/*.json |
archive | the AIP files (re-materializable from the journal) |
passports/*.json |
projector | the passport document store |
| seed assets | the operator | reproducibility of the initial state |
For a tenant, all of the above live inside tenants/<name>/ (plus
run/tenants/<name>/ for logs and pids, which are not state).
Why backups can run hot
Section titled “Why backups can run hot”Every journal is append-only JSONL; services replay them on start. No service rewrites its journal, so a file copy taken while services append is at worst a torn tail, and every journal replay checks sequence, digest, and torn-tail integrity, refusing to continue past a torn record rather than silently accepting a partial line.
The consistency point across services is the transparency log’s signed
tree head: at backup time, record GET /log/tree/head (tree size + root +
signature). A restore that replays journals and then verifies the tree head
against the recorded consistency point proves the backup is coherent across
services, because the log anchors the archive snapshots and the issuer’s verdicts
reference the log head.
$ curl -s http://127.0.0.1:8392/tree/head | jq '{tree_size, root: .root[0:16], log_id}'{ "tree_size": 5, "root": "d23b199b96ed73ea", "log_id": "unidpp-pilot-log-1"}The signature over the full head (in the same response) is what makes the point verifiable, rather than merely recorded.
The backup contract (unidpp-ops backup <tenant>)
Section titled “The backup contract (unidpp-ops backup <tenant>)”$ ./unidpp-ops backupbackup: unidpp-reference-20260908T053255Z files: 27 consistency point: size 5 root d23b199b96ed73ea7a7e... archive: backups/unidpp-reference-20260908T053255Z.tar.gz
$ ./unidpp-ops verify backups/unidpp-reference-20260908T053255Z.tar.gzverified: 27 member(s), consistency point size 5 root d23b199b...A tampered archive fails verification naming the corrupted member; a restore of the reference deployment’s backup served the identical 1 531 registry items, with parity proven.
What the tooling must produce, and what you should demand of any hand-rolled equivalent:
- Contents: the operator manifest, every journal, the snapshot directory, the passport store, and the seed assets of the tenant.
- A manifest-of-the-backup: what was copied, when, and a SHA-256 per file, so the backup is verifiable the same way everything else in the system is.
- The consistency point: the log tree head recorded at snapshot time (from the live log service if the deployment declares one).
- Taken hot: services keep running; append-only journals make this sound (above).
- Versioned: backup files carry the deployment name and timestamp; nothing overwrites a previous backup.
The restore contract (unidpp-ops restore <archive> <tenant>)
Section titled “The restore contract (unidpp-ops restore <archive> <tenant>)”- Unpack into a fresh tenant directory; refuse to overwrite an existing
tenant without an explicit
--force. - Verify checksums before writing anything; a tampered or corrupt archive is a hard failure naming the file.
- Validate the manifest with
unidpp-config validate; a restore of a manifest that no longer validates is refused. - Start via
unidpp-stack tenant <tenant> up; journals replay.
Acceptance (the test the tooling must pass): backup → restore → start → the registry serves the same item count as before, and the log verifies its head against the recorded consistency point.
Manual procedure (works today)
Section titled “Manual procedure (works today)”# 1. Record the consistency point (if the deployment declares a log).$ curl -s http://127.0.0.1:8392/tree/head > /tmp/tree-head-$(date -u +%Y%m%dT%H%M%SZ).json
# 2. Copy the tenant's state (services stay up).$ tar -C unidpp-pilot-data -czf acme-backup-$(date -u +%Y%m%dT%H%M%SZ).tgz \ tenants/acme
# 3. Checksum the archive (the manifest-of-the-backup, minimal form).$ shasum -a 256 acme-backup-*.tgz > acme-backup-*.tgz.sha256
# Restore into a fresh directory:$ mkdir -p unidpp-pilot-data/tenants/acme-restored$ tar -C unidpp-pilot-data/tenants/acme-restored -xzf acme-backup-<stamp>.tgz# (adjust the manifest's state_file paths if the directory name changed)$ unidpp-config validate unidpp-pilot-data/tenants/acme-restored/unidpp-operator.yaml$ ./ops/target/release/unidpp-stack tenant acme-restored up # journals replayThe console’s Backups page lists backups in the configured directory, triggers one by invoking the program (the console never reimplements the logic), and shows the consistency point. It is session-gated like every console mutation.
What backups do not include
Section titled “What backups do not include”- Secrets. The manifest carries
${VAR}references; the values live in your secret manager. A restored deployment needs the same environment — by design, a stolen backup yields no tokens. - Signing keys. Keyrings derive from seed material in the environment
(
UNIDPP_ISSUER_SEED,UNIDPP_LOG_SEED, …). Back up the seed configuration the same way you back up other secrets: separately, and more carefully. Lose the seed, lose the identity: re-issued anchors do not verify against previously published ones. - Ephemeral runtime:
run/pids and logs are not state.