Dara Docs
ReferenceOperations

Backup and restore

MethodPostgreSQL with pgBackRest: full, differential and incremental backups plus continuous WAL archiving, encrypted, to two repositories (one off-site)
Drillmake backup-drill (deploy/backup/restore-drill.sh): point-in-time restore of a copy of the demo database, verified table by table
Last drill2026-10-30, all checks passed (§4)

1. What is protected

DataWhereProtectionRecovery
Application database: ledger, orders, customers, audit, blockchain intents with their signed envelopes, indexer projections, scan schemaPostgreSQLSynchronous replica + pgBackRest (two encrypted repositories)Replica promotion, or point-in-time restore (§3)
Account manifest, configurationGit / deployment secretsVersion control and the secret storeRedeploy
Stellar chain dataThe network itself, our RPC nodesNot backed up: nodes resync; the ledger is public and finalSTELLAR_RPC_RUNBOOK.md
KeysHSM / KMS, human signers' hardware keysNever in database backups (../security/KEY_MANAGEMENT.md)KEY_MANAGEMENT.md
Monitoring dataPrometheus, LokiNot backed up (operational)—

The chain is the second copy of every token balance: after a restore, reconciliation compares the restored ledger with the chain. Intents whose transactions applied after the restore point are found by their MEMO_HASH (the indexer re-reads the ledgers after its restored cursor) and must be resolved before trading resumes (§3 step 5).

2. Schedule and targets

ItemValue
Full backupWeekly; retain 4 locally, 8 off-site
Differential / incrementalDaily / hourly
WAL archivingContinuous, archive_timeout = 60 s
Verificationpgbackrest check after every backup; restore drill quarterly and after every PostgreSQL major upgrade
RPO0 with the synchronous replica; ≤ 60 s from the repositories
RTOReplica promotion: minutes. Repository restore: measured 19 s for the demo database (§4); size-proportional

3. Restore procedure (point in time)

  1. Stop the workers and APIs (no writes). Pause trading is implicit: the gate state ages out.
  2. Choose the target time (before the incident) and restore into an empty data directory: pgbackrest --stanza=dara --type=time --target=<time> --target-action=promote restore.
  3. Start PostgreSQL, then one worker only: startup verification checks the manifest against the chain.
  4. Let the indexer catch up from its restored cursor; it re-reads every ledger since, so every on-chain movement after the restore point appears again, linked to its intent by MEMO_HASH.
  5. Run reconciliation. Differences after a restore are expected exactly where intents applied on-chain after the restore point; resolve each as CHAIN_OPERATION_UNRESOLVED (INCIDENT_RESPONSE.md) before trading resumes.
  6. Start the APIs; the gate reopens after the hold-down.

4. Drill results

deploy/backup/restore-drill-result.md keeps every run. 2026-10-30, demo database (602 rows, 37 tables): full backup 22 s (3.8 MB compressed and encrypted); restore to the target time and promotion 19 s; every table identical to the target state; the write after the target absent; the table dropped after the target back; no unbalanced ledger transaction; append-only and balance triggers present; indexer cursor restored.

On this page