Ir al contenido

Backup & upgrades

Taranac backs up its configuration, not its history. A backup captures everything that defines how the system authenticates and authorises — devices, policies, profiles, users, groups, RBAC, the internal CA, daemon configs and the host secrets needed to bring the stack back up — and packages it into a single encrypted archive. Logs, live sessions, alerts and other dynamic data are deliberately excluded.

Backups are created and managed from the admin UI under Settings → Backup & Recovery. Restore is not in the UI — it is destructive (it erases the current configuration) so it runs from a CLI, off the API, and verifies your master key before it touches anything. This page covers what is in an archive, scheduling and retention, the two-phase recovery flow, how the upgrade/version gate works, and how backups relate to high availability.

A backup archive: an outer tar holding a plaintext manifest.json and an encrypted payload.enc (db, certs, host_files, daemon_configs), sealed by the master key that is stored separately.

An archive is named taranac-backup-<UTC-timestamp>.tar. It is an outer tar with two members:

  • manifest.json — plaintext, non-secret metadata. It records the format version, creation time, trigger (manual/scheduled), the Taranac version (app_version), the database schema revision (alembic_head), a short master-key fingerprint, and an encrypted canary token. Because it is readable without the key, recovery can verify the right master key before decrypting anything.
  • payload.enc — the actual contents, an inner tar encrypted with the master key (Fernet).

The encrypted payload contains:

ComponentBadgeWhat it isAlways included?
Database dumpdbA data-only dump of the configuration tables (dynamic tables excluded)Yes — not a toggle
CertificatescertsThe internal CA plus all server key/certificate pairsOptional (include_certs)
Host fileshost_filesThe active .env file and Docker Compose file — i.e. the non-database secrets: master key, API keys, DB passwordOptional (include_host_files)
Daemon configsdaemon_configsGenerated TACACS+ / RADIUS / NAC config snapshots (informational — regenerated from the DB on restore)Optional (include_daemon_configs)

A leaked archive is useless without the master key.

The boundary between “config” (backed up) and “dynamic” (excluded) is defined in one place in the product, so the backup side and the restore side never disagree. Excluded from the database dump:

  • Log tables (authentication, sessions, accounting, audit logs, LDAP sync logs)
  • Live NAC sessions, the alert queue and firing alerts, MFA challenges
  • Ephemeral tokens (refresh tokens, password-reset tokens, certificate-download tokens) and password-reuse history
  • Endpoint discovery staging (auto-repopulates from live traffic)
  • The IEEE OUI vendor database (re-synced on a schedule)
  • HA cluster-runtime state — the node roster (cluster_nodes), its join tokens (cluster_join_tokens), and per-node service health (node_service_health). This describes this physical cluster, not portable configuration; the running node keeps its own current roster on restore, so a stale roster can’t resurrect decommissioned or foreign nodes
  • The schema-version row (the restore target is already at the right schema)

Everything else — your real configuration — is included.

The Backup & Recovery page has three sections: schedule & retention, the archive list, and a recovery-instructions panel. Access is gated by the backup RBAC permission set (view, create, download, delete, manage); if you lack backup.view the page is empty.

Backup & Recovery settings page in the Taranac admin UI The Backup & Recovery page: schedule and retention on top, the archive list with per-archive badges below.

Editable settings (saving requires backup.manage):

SettingDefaultMeaning
schedule_enabledoffMaster toggle for automatic backups
interval_hours24Hours between scheduled backups (floored to a 1-hour minimum)
retention_count5How many archives to keep on disk; older ones are pruned. Applies to manual backups too, not only scheduled
include_certsonPack the internal CA and TLS certificates
include_daemon_configsonPack the generated TACACS+/RADIUS/NAC config files
include_host_filesonPack the .env and Compose file (the host secrets)

The database dump is always packed; there is no toggle to exclude it.

When scheduling is enabled, a background worker runs on the configured interval, creates one archive, and prunes to the retention count. A scheduled-backup failure is loud: it records a BACKUP_FAILED audit event and raises a firing alert (cleared automatically on the next successful run). The worker never crashes the scheduler.

Create backup now (backup.create) builds an archive synchronously — it usually takes a few seconds. On success the archive list refreshes.

Each row shows the creation date (in your configured timezone), the filename with its app_version, the size, the trigger badge (manual or scheduled), and “included” badges (db, certs, host_files, daemon_configs). Two actions:

  • Download (backup.download) — streams the .tar through the authenticated API; the file never appears in a URL. Store it somewhere safe and off-box.
  • Delete (backup.delete) — asks for confirmation with the exact filename, then permanently removes the archive. This cannot be undone.

Recovery is CLI-only and destructive. A fresh Taranac deploy is not empty — startup migrations and seeds build a working default system — so recovery first wipes the current configuration and then loads the backup. That is why it is a deliberate, off-the-API action.

The intended flow:

  1. Deploy a fresh, healthy Taranac and log in as the default admin. Confirm the deploy itself works (this separates “deploy failed” from “recovery failed”).
  2. Have the original master key at hand.
  3. Run the two phases below.

The recovery panel in the UI documents the same steps; there is no recover-from-browser button by design.

A helper script runs the in-container steps and prints the by-hand host steps in between:

Terminal window
deploy/taranac-restore.sh prod taranac-backup-YYYYMMDDTHHMMSSZ.tar
# or: deploy/taranac-restore.sh dev <archive>.tar

Verify the key against the archive, then decrypt and extract the host secrets and certificates:

Terminal window
docker compose --env-file .env -f docker-compose.prod.yml exec api \
python -m app.scripts.restore host /app/backups/<archive>.tar --out /app/backups/restore

Then put the original .env, Compose file and certificates back and bring the stack up with the original secrets:

Terminal window
cp ./backups/restore/env/env .env
cp ./backups/restore/compose/compose.yml docker-compose.prod.yml
docker compose --env-file .env -f docker-compose.prod.yml exec api \
sh -c 'cp -a /app/backups/restore/certs/. /opt/taranac/certs/'
docker compose --env-file .env -f docker-compose.prod.yml up -d

You can also pass an explicit key with --master-key <KEY> instead of relying on the running container’s loaded key.

Once the stack is healthy again on the restored secrets, restore the configuration:

Terminal window
docker compose --env-file .env -f docker-compose.prod.yml exec api \
python -m app.scripts.restore db /app/backups/<archive>.tar

Phase 2 verifies the master key, the version and the schema, asks you to type yes to confirm, then in one transaction truncates the configuration tables and reloads the dump. The HA cluster-runtime tables (cluster_nodes, cluster_join_tokens, node_service_health) are left untouched — the running node keeps its own current cluster membership. An older archive taken before those tables were excluded is filtered on the way in, so a stale roster is never reloaded. Restore then regenerates the TACACS+/RADIUS/NAC daemon configs from the restored database and records a BACKUP_RESTORED audit event. A full stack restart afterwards is recommended so every service re-reads the restored certificates and configuration.

Add --yes to skip the interactive confirmation (for automation).

Phase 2 refuses to run unless three checks pass:

GateCheckOverride
Master keyThe archive canary decrypts with the loaded keynone — a key mismatch always aborts
VersionArchive app_version equals the running version--force
SchemaArchive alembic_head equals the current DB schema revision--force

The master-key gate cannot be overridden. The version and schema gates can be bypassed with --force, but only do so when you are certain the configuration is compatible — see upgrades below.

Taranac ships as a single platform stack: backend, frontend, captive portal and the TACACS+/RADIUS/NAC daemons all roll together under one version and one Git tag. (The optional taranac-mfa push service versions on its own line.) The daemons are downstream consumers of config the backend generates, so they cannot be released separately — what actually guarantees compatibility is the config-format contract between the backend and the daemons, not the version number alone.

On every start, the API container applies database migrations automatically (alembic upgrade head) before serving traffic, and regenerates the internal CA/server certificates if they are missing. Upgrading is therefore: pull the new images, recreate the stack, and the container migrates the schema forward on boot.

Terminal window
docker compose --env-file .env -f docker-compose.prod.yml up -d --build

Backup before you upgrade — and why version matters

Section titled “Backup before you upgrade — and why version matters”

Because a restore is gated on exact version and schema match, the safe recovery story is: a backup taken on version X restores cleanly onto a deployment running version X. After you upgrade to Y, an older X archive will hit the version/schema gate.

The decision guidance:

You have……and you want to restore ontoDo this
A backup from the running versionThe same versionRestore directly — all gates pass
A backup from an older versionA newer deploymentRe-deploy the older version, restore there, then upgrade forward (so migrations run normally); avoid --force
A backup whose version you can’t matchA newer deployment--force overrides the version/schema gate — only if you are confident the schema is compatible; not the default path

Taranac ships a turnkey high-availability mode as a licensed Pro feature: the stack runs across two or more hosts with a Patroni-managed primary/replica PostgreSQL cluster (etcd coordination, optional witness for two-node setups), and automatic failover keeps authentication answering when a host goes down. All durable state lives in PostgreSQL, so replicating the database is what makes the system highly available. See High availability for the full architecture, prerequisites, enablement, and day-2 operations, and Licensing for how HA is unlocked.

Backups complement HA — they do not replace it. HA protects against a host or process failure; it does not protect against operator error, a bad upgrade, or corruption that replicates to every node. Whether or not you run HA, keep regular, off-box backups plus a securely stored master key as your recovery-of-last-resort. Note that a configuration backup deliberately excludes the HA cluster-runtime tables (see Configuration vs dynamic data above), so a restore never disturbs live cluster membership — the running node keeps its own roster.

CommandPurpose
python -m app.scripts.restore host <archive> --out <dir>Phase 1: verify key, extract env/ + compose/ + certs/
python -m app.scripts.restore host … --master-key <KEY>Decrypt with an explicit key instead of the loaded one
python -m app.scripts.restore db <archive>Phase 2: verify gates, wipe config tables, reload the dump, regenerate daemon configs
python -m app.scripts.restore db … --yesSkip the interactive confirmation
python -m app.scripts.restore db … --forceOverride the version/schema gate (the key gate still applies)
deploy/taranac-restore.sh <dev|prod> <archive>Guided wrapper for the whole runbook

Backups emit BACKUP_CREATED, BACKUP_DELETED, BACKUP_FAILED, BACKUP_SETTINGS_CHANGED and BACKUP_RESTORED — review them in the audit log.