Back up and restore VTA state
By the end of this guide, you have a password-encrypted backup of your VTA’s operator state, and you know how to restore it.
A VTA backup captures the keys, identities, contexts, and access control configuration of a running VTA at a point in time, as a single encrypted .vtabak file. Restoring it replaces all current data in the target VTA. For what the keys inside it are derived from, and why the master seed matters to recovery, see Keys and contexts.
Rebuilding a lost VTA by hand means re-minting every key, re-provisioning every application, and reconstructing the access control list (ACL) from memory, with the original DIDs gone. A backup is what turns that into a restore. Note that a few keyspaces are deliberately excluded, so a restore is not a complete rebuild on its own; see Known gaps.
Use this guide when:
- You are putting a VTA into production and need a recovery position before you depend on it.
- You are migrating a VTA to a new host.
- You want to clone a VTA environment, for example to seed staging from development.
- You are about to make a change you may need to roll back.
Exporting a backup
pnm backup exportYou are prompted to enter and confirm a password (minimum 15 characters). The backup is saved to a .vtabak file in the current directory:
vta-backup-<did-tail>-<timestamp>.vtabak<did-tail> is the final segment of the VTA’s DID, not the full DID value.
Including audit logs
Audit logs are excluded from the default export because they can be large. Add --include-audit to include them:
pnm backup export --include-auditSpecifying the output path
pnm backup export --output /path/to/my-backup.vtabakWhat is backed up
| Included | Not included |
|---|---|
| Keys (derived and imported) | Sessions |
| ACL entries | DID templates (known gap: upload separately after restore) |
| Contexts (BIP-32 key hierarchy) | Vault secrets (known gap: re-import after restore) |
| WebVH DID records and logs | Issued holder credentials (known gap: re-issue after restore) |
| Imported secret material (KEK-wrapped) | Cache |
| Consent records and approvers | Service state (protocol management, drain set) |
| Agent memory and application state | Passkey enrolment state |
| Holder identity (persona) | Bootstrap nonces |
| Operator security policy | |
| Messaging room groups and invitations | |
Audit logs (with --include-audit) |
Known gaps
DID templates, vault secrets, and issued holder credentials are durable operator or holder data but are currently excluded from the backup. After restoring:
- Re-upload any custom DID templates using
pnm did-templates create. - Re-store any vault entries your apps depend on using
pnm vault upsert. - Re-issue any holder credentials your VTA had previously issued.
Vault secrets are service-consumer secrets stored in the
pnm vaultstore, a separate keyspace that is currently excluded.
Encryption details
Backups are encrypted with Argon2id + AES-256-GCM:
| Parameter | Value |
|---|---|
| KDF | Argon2id |
| Memory cost | 64 MiB (OWASP-recommended profile) |
| Iterations | 3 |
| Parallelism | 4 threads |
| Encryption | AES-256-GCM |
| Salt | 32 bytes, random per export |
The KDF parameters are stored in the backup envelope. On import, the VTA validates that the parameters fall within accepted bounds. Extreme values are rejected to prevent memory exhaustion, which matters most for Nitro Enclave deployments.
Inspecting a backup before importing
Use --preview to see what a backup contains without applying any changes:
pnm backup import my-backup.vtabak --previewOutput:
Backup file: my-backup.vtabak
Source DID: did:webvh:...
Created: 2026-06-18 10:00:00 UTC
Version: 1.2.3
Audit: false
Keys: 12
ACL entries: 5
Contexts: 3
Audit logs: 0
Preview only — no changes applied.Importing a backup
All existing VTA data, including data added since this backup was generated, will be replaced. This action is irreversible and cannot be rolled back once confirmed.
pnm backup import my-backup.vtabakThe import flow:
- Metadata display: shows source DID, creation time, version, and whether audit logs are included.
- Password prompt: enter the backup password (not confirmed on import).
- Preview: shows counts of keys, ACL entries, contexts, and audit logs to be restored.
- Confirmation: you must type
yesexactly to proceed. - Apply: all current data is replaced with the backup contents.
Compatibility rules
| Condition | Result |
|---|---|
| Restoring to a fresh (unconfigured) VTA | Always accepted |
| Restoring to a VTA with the same DID | Accepted |
| Restoring to a VTA with a different DID | Rejected with 400: source DID does not match the running VTA’s DID |
The DID mismatch check prevents accidentally restoring the wrong backup to a configured VTA.
To restore to a different VTA (e.g. migration), you must factory-reset or reinstall the target VTA first, then import.
After import
- The VTA restarts to apply the new key hierarchy.
- If the VTA DID has changed (cross-VTA migration), you must re-authenticate with credentials from the restored backup.
- Re-upload any DID templates, re-import any vault secrets, and re-issue any holder credentials (see Known gaps).
- Inform any integrations of the new VTA DID if it has changed.
Confirm
Test 1: the exported file exists and previews cleanly
Run this against the file pnm backup export wrote, before you rely on it for recovery. A backup you have never read back is not yet a backup.
pnm backup import vta-backup-<did-tail>-<timestamp>.vtabak --previewBackup file: vta-backup-<did-tail>-<timestamp>.vtabak
Source DID: did:webvh:...
Created: 2026-06-18 10:00:00 UTC
Version: 1.2.3
Audit: false
Keys: 12
ACL entries: 5
Contexts: 3
Audit logs: 0
Preview only — no changes applied.Test 2: the counts match the VTA you exported from
Compare the preview counts against the live VTA:
pnm keys list
pnm acl list
pnm contexts listThe Keys, ACL entries, and Contexts totals in the preview match what these commands return. A lower count means the export ran before the most recent changes.
Test 3: the password is the one you recorded
The preview above reads only the envelope. Confirm the password decrypts the payload by running the import against a non-production VTA, or accept that an untested password is a recovery risk: there is no password recovery path for VTA backups.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Import rejected with “source DID does not match” | The target VTA has a different DID from the backup source. | Factory-reset or reinstall the target VTA first, then retry the import. See Compatibility rules. |
| Password rejected on import | Wrong password entered, or the backup was exported on a different machine or version. | Re-export with the correct password. There is no password recovery path for VTA backups. |
| Vault secrets missing after restore | Vault secrets are excluded from the standard backup format. | Re-import vault secrets using pnm vault upsert. See Known gaps. |
| DID templates missing after restore | DID templates are excluded from the standard backup format. | Re-upload DID templates using pnm did-templates create. See Known gaps. |
| Service cannot authenticate after restore | Service credentials were minted after the backup was taken. | Re-provision affected services using pnm bootstrap. |
Next steps
Glad to hear it! Please tell us how we can improve more.
Sorry to hear that. Please tell us how we can improve.
Thank you for sharing your feedback so we can improve your experience.