A defensible DR and business-continuity posture for on-premise Versus — what to protect, how much data you can lose and how fast you come back (RPO/RTO), how to back up and restore, high availability versus disaster recovery, multi-site and air-gapped DR, and a step-by-step recovery runbook.
A Versus outage does not stop the network it manages — your F5s, firewalls, routers and switches keep forwarding. DR here restores the management, automation and record-keeping layer, not production traffic.
A perfect database backup is useless without the FIELD_ENCRYPTION_KEY that decrypts its sensitive columns. Escrow it separately — and test that you can decrypt after a restore.
Everything you must reconstruct lives in a small number of places. Protect these and you can rebuild the whole system.
| Component | What it holds | How to protect |
|---|---|---|
| PostgreSQL | Source of truth: inventory, config snapshots, workflows & runs, tickets/audit, users & roles, and the ciphertext of every secret | WAL + PITR or scheduled dumps, off-box and off-site |
| Object storage | Durable device-config backups + media (PCAPs, firmware, artifacts) | Bucket versioning + off-site replication |
FIELD_ENCRYPTION_KEY | Fernet key that decrypts encrypted columns (device credentials, vault secrets) | Escrow separately from the DB |
SECRET_KEY | Django signing / session key | Escrow with the field key |
.veslic license | Signed, node-locked license + activation state | Keep the file (+ any re-host file) in your config store |
| Config / environment | DATABASE_URL, auth backends, OIDC_*, BACKUP_S3_*, values.yaml | Treat as code; version it |
| Collectors | Outbound-only agents; in Mode A their local vault holds on-prem credentials | Re-enrollable; back up local vault material |
FIELD_ENCRYPTION_KEY (and SECRET_KEY) must be escrowed separately from the database. Lose the field key and encrypted data — device credentials and vault secrets — is unrecoverable even from a flawless DB backup; let it leak with a backup and that ciphertext is no longer protected. Keep the keys in a sealed vault, and make sure that store is itself backed up.RPO = how much data you can afford to lose (the age of your newest usable backup). RTO = how long you can be down. Your numbers follow the form factor you deployed (see the On-Premise Installation Guide) and the cadence you pick.
| Form factor | Achievable RPO | Achievable RTO | How |
|---|---|---|---|
| A · Single-node appliance | Last snapshot/dump (min → 24 h) | Minutes → hours | VM snapshot + off-box dump + BACKUP_S3_* |
| B · Kubernetes (Helm) | Seconds → minutes | Seconds (auto-failover) · minutes (PITR) | Operator Postgres (CloudNativePG) + distributed MinIO |
| C · Clustered appliances + LB | Your Postgres HA lag | App: auto via LB · DB: your failover | Shared external Postgres + streaming replication + Patroni |
Postgres is the one thing you cannot lose. At minimum, take a nightly logical dump off the box:
pg_dump --format=custom --no-owner \
"postgres://versus:PASS@pg-primary:5432/versus" \
> versus-$(date +%F).dumpFor a low RPO, add continuous WAL archiving + base backups → point-in-time recovery(pgBackRest, Barman, or the CloudNativePG operator on Kubernetes). Encrypt backups at rest and store them off-box and off-site — a backup on the same VM or array is not a backup.
Point BACKUP_S3_* at durable, versioned storage and replicate it off-site:
BACKUP_S3_BUCKET=versus-backups
BACKUP_S3_ENDPOINT=https://minio.yourco.internal # omit for AWS S3
BACKUP_S3_REGION=us-east-1 # 'auto' for R2
BACKUP_S3_ACCESS_KEY_ID=...
BACKUP_S3_SECRET_ACCESS_KEY=...Enable bucket versioning (so an overwrite or ransomware event is recoverable) and cross-site replication (S3/R2 rules, or MinIO site-replication). Durable device-config backups land here too — see Backup & Config Protection.
FIELD_ENCRYPTION_KEY + SECRET_KEY — escrow in your secrets manager or a sealed offline copy, separately from the database..veslic license — keep the file (and any re-host file) with your config. See Activating an On-Premise License.values.yaml — version it like code so a rebuild is reproducible.Collectors are effectively stateless and re-enrollable — they dial the gateway outbound over a bearer-authenticated TLS channel on 443. In Mode A (local vault, credentials never leave your network), back up each collector host's vault material per your collector runbook; otherwise a rebuilt collector simply re-enrolls.
Rebuilding from nothing, in order. Order matters — the keys must be in place before the data, or encrypted columns won't decrypt.
Appliance VM, Compose host, or Helm release. Don't restore old data into a newer schema — match the version first, then upgrade forward.
Set SECRET_KEY and FIELD_ENCRYPTION_KEY to the exact values used when the data was encrypted. A mismatched field key means the DB restores but credentials and vault secrets won't decrypt.
pg_restore the latest dump, or recover WAL to your target point in time.
Point BACKUP_S3_* at the replicated bucket and confirm device backups and media are present.
New hardware changes the node fingerprint, so you may need a re-host file; the licensing grace period keeps you running meanwhile. Keep a spare/offline .veslic for exactly this moment.
GET /api/updates/health/ returns OK once the DB is reachable and migrations have run.
They dial the gateway outbound — update the gateway address (or keep a stable DR DNS/VIP for it) and they reconnect; re-enroll any that can't.
Log in, confirm inventory and history are present, open a vaulted secret (proves the field key decrypts), and run one discovery or backup.
They solve different problems, and you generally want both:
DELETE or a ransomware encryption to every replica in seconds. You still need point-in-time backups to recover state, not just availability.When you run more than one app node (Option C), pin the per-process singletons so nodes don't double-fire or diverge: run the schedulers/pollers on one node (DISABLE_INPROC_SCHEDULERS=1 on the others), enable LB sticky sessions, and share object storage and the media path. The installation guide has the full table.
To survive a whole-site loss, run a warm standby at a second site:
FIELD_ENCRYPTION_KEY, SECRET_KEY, and a valid .veslic must be at the DR site before you need them.RTO is then promote + boot + DNS — minutes, not hours.
Nothing here requires the internet:
.veslic file re-uploaded on the recovered node; keep spare/re-host files on hand so licensing never blocks a recovery, and understand the grace period.Versus fails soft, which buys you time during an incident:
In your own runbook, note that while Versus is being restored, device changes revert to your out-of-band process — and the restored system re-discovers current state on its next sweep.
A backup you have never restored is a hypothesis. Prove it on a schedule:
| What | Frequency | Where | Protects against |
|---|---|---|---|
| Postgres dump / WAL archive | Nightly, or continuous (PITR) | Off-box + off-site | Data loss, corruption, ransomware |
| Object-store versioning + replication | Continuous | Second site | Overwrite, ransomware, site loss |
| Field key + secret key escrow | On change | Sealed vault, separate from DB | Unrecoverable encrypted data |
.veslic (+ re-host file) | On renewal | Config store, DR site | Licensing blocking a recovery |
Config / values.yaml | On change | Version control | Non-reproducible rebuilds |
| Full restore drill | Quarterly | Isolated env | Untested, unusable backups |