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 key files
Section titled “The key files”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:
| File | What it is | If it is lost or replaced |
|---|---|---|
keys/node-<kid>.pem | The 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.key | 32 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.key | The 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.key | LiveKit’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.key | The 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.
What to back up
Section titled “What to back up”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:
docker compose stop tavrndocker compose exec -T db pg_dump -U tavrn -Fc tavrn > backup/tavrn-$(date +%F).dumptar -C . -czf backup/tavrn-data-$(date +%F).tar.gz datadocker compose start tavrnWithout 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.
Restoring
Section titled “Restoring”A restore brings back the database and the data volume from the same backup, so the keys match the data.
- 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 thedatadirectory (includingkeys/) from the same backup. - Start the image version the backup was taken with, or a newer one (migrations only go forward; an older binary refuses a newer schema).
- Check
docker compose logs tavrn,/readyzand 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.