Skip to content

Backup, restore, and encryption

Backup

Run deploy/backup. It creates a timestamped, checksummed directory under backups/ containing a custom-format Postgres dump, local blobs/exports/logs/integration files, speech models (STT + TTS voices), optional observability reports, Ollama models, the source revision, and a copy of .env when present. Set BACKUP_DIR to write to encrypted removable or network storage.

Verify without restoring:

cd backups/semaje-YYYYMMDDTHHMMSSZ
shasum -a 256 -c SHA256SUMS
docker compose exec -T postgres pg_restore --list < postgres.dump >/dev/null
tar -tzf app-data.tar.gz >/dev/null
tar -tzf stt-models.tar.gz >/dev/null

Restore drill

Use a disposable deployment first. deploy/restore <backup-directory> --yes stops application writers, verifies checksums, restores Postgres and data/model volumes, reapplies forward migrations, and restarts the stack. It writes backed-up configuration to .env.restored for manual review; it never silently replaces active secrets.

After restore, check docker compose ps, /api/health, transcript count, one audio playback, one export, and the model manager. Keep a dated restore-drill record outside the server.

Encryption at rest

Use full-volume encryption beneath Docker volumes: LUKS2 on Linux, FileVault on macOS, BitLocker on Windows, or encrypted ZFS datasets. Put pgdata, blobdata, model volumes, backups, and .env on the encrypted volume. For S3/MinIO storage, require server-side encryption and TLS. Keep encryption keys in the host secret manager, not Compose files or Git, and rotate JWT, invite, webhook, SMTP, calendar, and object-store credentials after a suspected host compromise.

Database and filesystem encryption protect powered-off media. They do not replace host access controls, TLS, least-privilege roles, audited exports, tested restores, or off-host backup copies.