Skip to content

Backup & Restore

Database schema upgrades are forward-only — there is no downgrade path. A backup taken with altavms backup is your only way to roll back, which makes it part of the upgrade routine, not an optional extra.

Terminal window
sudo altavms backup --output /root/

There’s no downtime: the database is snapshotted with SQLite’s VACUUM INTO, which takes a consistent point-in-time copy while the service keeps writing, and the copy is already checkpointed — the archive never contains WAL/SHM sidecar files, so the “restored an old WAL onto a new database” corruption class can’t happen. The source database is integrity-checked first; a backup of a damaged database is refused rather than overwriting your last good archive.

altavms-backup-<host>-<timestamp>.tar.gz
└── altavms-backup-<host>-<timestamp>/
├── manifest.json what's inside, schema version, encryption key ids
├── altavms.db consistent database snapshot
├── config.yaml
├── altavms.env secrets — omit with --no-secrets
├── maps/… floor-plan images — omit with --no-maps
└── systemd/altavms.service reference only; restore never writes it

Included by default:

  • altavms.env (secrets). The encryption key that protects every encrypted column — camera and Alta credentials, storage and SMTP secrets, webhook signing keys — exists only in this file. An archive without it can’t decrypt the database it’s paired with, so secrets are included by default; the archive is written 0600.
  • maps/. Floor-plan backgrounds are the only operator-uploaded files outside the database, and the database rows referencing them travel in the same archive — leaving the images out would make a “successful” restore quietly produce maps with missing backgrounds.

Excluded, with the reason recorded in the manifest:

  • Clips and screenshots — retention-managed and regenerable; including them would make routine backups multi-gigabyte.
  • HLS recordings — they live on the Alta server’s own storage, never on the VMS host.
  • The binary — its version is recorded in the manifest, but a backup is a data rollback, not a code rollback.
Terminal window
sudo altavms restore /root/altavms-backup-<host>-<timestamp>.tar.gz

The sequence is deliberately careful:

  1. Everything is verified before anything on disk changes — the manifest, every file’s checksum, and the archive’s contents are checked before any write. Treat an archive from someone else as you would any untrusted file.
  2. Schema check. An archive from a newer build is refused outright — upgrade the binary first. An older archive restores with a warning: the service will forward-migrate it on next start, which is irreversible.
  3. Key check. If the archive has no altavms.env, its recorded encryption-key ids must match a key you currently hold, or the restore refuses (--force-key-mismatch overrides this).
  4. Refuses while the service is running. Pass --stop-service to have it stop the service for you — restore never starts it back up afterward, so problems surface before the service does.
  5. Typed confirmation. You must type restore <this hostname> to proceed — a runbook command pasted onto the wrong machine fails instead of running.
  6. A safety backup of the current state is taken first. If that fails, nothing else happens.
  7. Files are replaced, stale WAL sidecars are removed, and the restored database’s schema is verified — any failure at this stage rolls everything back.

Afterwards, bring the service back up yourself:

Terminal window
sudo altavms doctor
sudo altavms start
sudo altavms status

altavms doctor reminds you to delete the pre-restore-* safety archive once you’re satisfied the restore is good.

A backup nobody has restored is not a backup. Run this quarterly:

Terminal window
sudo altavms restore <latest-archive> --dry-run

--dry-run runs the full verification — manifest, checksums, schema, and key compatibility — and prints what it would do without writing anything. It proves the archive is intact and restorable on the machine that would actually need it.

Restoring onto different hardware is supported — the command warns when the archive comes from another host, and because the typed confirmation always names the host you’re currently on, a runbook line copied to the wrong machine still fails safely. After a cross-host restore, review http.allowed_origins in the restored config before starting — it may still name the old host.

A cron line is enough; the command needs no coordination with the running service:

15 3 * * * root /usr/local/bin/altavms backup --output /var/backups/altavms/ >>/var/log/altavms-backup.log 2>&1

Rotate old archives yourself, e.g.:

Terminal window
find /var/backups/altavms -name 'altavms-backup-*.tar.gz' -mtime +30 -delete

Each archive contains your encryption key by default — apply the same access controls to your backup storage that you apply to /etc/altavms/altavms.env.