Skip to main content

Keys and backups

The node’s keys live in the data volume next to the uploaded files; they are backed up and restored together with the database, because neither is usable without the other.

The data volume (./data, mounted at /data, TAVRN_DATA_DIR) holds the uploaded files in blobs/ and, in keys/, the node’s keys.

All of them are created at the first start with mode 0600:

FileWhat it isIf it is lost or replaced
keys/node-<kid>.pemThe node’s Ed25519 signing keys (federation, tokens). All keys in the directory are published in /.well-known/tavrn; the newest one signs. A generated key’s kid is its creation date plus a random suffix (20261011-3f9a1c).Other nodes no longer trust the node’s identity: a node that starts without this directory generates a new key, and peers that knew the old one refuse the node until their operators unblock it (a lost key is never recovered by restarting).
keys/secrets.key32 random bytes that encrypt data at rest such as the users’ TOTP secrets and the credentials of external file stores, and the single-use values in the cache with several instances. Never rotated.Every TOTP enrollment becomes unusable (users then need a passkey, a recovery code or an admin reset of their second factor), and files channels on external stores need their credentials entered again.
keys/storage.keyThe storage key: wraps the per-file keys of every stored file (attachments, avatars, headers, room icons, emojis, soundboard clips). keys/storage.key.next exists only during a rotation.Every stored file is unreadable; the node refuses to start when the file is missing or does not match the stored keys.
keys/livekit.keyLiveKit’s API key and secret (<key>: <secret>).Regenerated at the next start, nothing lost. With several instances all must use the same file.
keys/vapid.keyThe VAPID key for web push: a P-256 private key, PKCS#8 PEM.Every browser push subscription becomes invalid: users must re-enable push on each device. No other data is lost.

Optional files you place there yourself, such as keys/oidc-client-secret for TAVRN_OIDC_CLIENT_SECRET_FILE, belong in the same backup. livekit.yaml (or livekit-<instance id>.yaml) in the data directory is regenerated at every start.

Never replace or delete the key files; restore them from the same backup as the database. The node never creates a new storage.key when one is expected: it refuses to start instead.

Back up the database and the data volume together, before every upgrade and regularly. They belong together: the database holds the wrapped file keys (blob_keys) and references every file in blobs/, the key files open both.

A consistent backup with a short downtime:

Terminal window
docker compose stop tavrn
docker compose exec -T db pg_dump -U tavrn -Fc tavrn > backup/tavrn-$(date +%F).dump
tar -C . -czf backup/tavrn-data-$(date +%F).tar.gz data
docker compose start tavrn

Without downtime, dump the database first and copy the volume afterwards: files uploaded in between are not referenced by the dump and are removed later by the housekeeping as orphans. Keep the key files in a second, separate place as well (they are small and change rarely: after the first start, a storage key rotation, a new signing key). Encrypt the backups; anyone holding the database, the volume and keys/ holds everything the node holds.

A restore brings back the database and the data volume from the same backup, so the keys match the data.

  1. Stop the node, restore the database dump (docker compose exec -T db pg_restore -U tavrn -d tavrn --clean --if-exists < backup/tavrn-<date>.dump) and the data directory (including keys/) from the same backup.
  2. Start the image version the backup was taken with, or a newer one (migrations only go forward; an older binary refuses a newer schema).
  3. Check docker compose logs tavrn, /readyz and a few attachments.

Because a storage key rotation does not re-encrypt the files, an old key together with an old database backup still opens the files of that time.


This page is generated from tavrn-node/docs/HANDBOOK.md (AGPL-3.0-only) when the website is built; its links were adapted for this site.