Server key management
This guide walks through every operational scenario for the server-side at-rest encryption key. For the cryptographic background see Encryption; this page is the runbook.
First start (fresh install)
At-rest encryption is opt-in. A new install runs without it until an administrator turns it on.
- Start pika. The process logs
server started; encryption not yet enabledand serves every request normally. - Open the web UI and complete the standard first-run admin account setup.
- Configure users, mounts, hooks, externals as needed — these all work in plaintext-at-rest mode.
- When you're ready to turn on encryption, navigate to Settings → Server encryption key → Enable encryption.
- Choose a strong passphrase. Save it in your password manager BEFORE clicking Enable — there is no recovery path.
- Confirm the passphrase. The form posts to
POST /api/v1/key/initialize(authenticated, requiressettings.manage); the server writes a verifier record into the settings table, re-seals existing sensitive settings under the new key, and stays unlocked for the rest of the process lifetime.
From here, every subsequent restart enters the locked state.
CLI / curl variant
curl -X POST -H "Cookie: pika_session=$SESSION" \
-H "Content-Type: application/json" \
-d '{"key":"correct-horse-battery-staple"}' \
https://localhost:8080/api/v1/key/initializeThe endpoint requires an authenticated session OR a token carrying settings.manage. $SESSION is the cookie value from /login/password.
Every-restart unlock
Pika starts in the locked state on every restart. Until unlocked:
/api/v1/info,/healthz,/login/*,/logout,/api/v1/me/*, and/api/v1/key/*continue to work.- Every other request returns
503withX-Pika-Locked: true. - The web UI's axios layer detects the header and renders the unlock screen automatically.
Steps:
- Open the web UI. The unlock screen appears.
- Paste the server key.
- Click Unlock. The form posts to
POST /api/v1/key/unlock. - Wrong key → 403 with a "wrong key" toast; the verifier protects against silent corruption.
CLI variant:
curl -X POST -H "Cookie: pika_session=$SESSION" \
-H "Content-Type: application/json" \
-d '{"key":"correct-horse-battery-staple"}' \
https://localhost:8080/api/v1/key/unlockStatus check
Always available, no auth required:
curl https://localhost:8080/api/v1/key/statusResponse:
{"initialized": true, "unlocked": false}initialized: false→ the verifier record doesn't exist yet (fresh install).unlocked: false→ server is locked; an admin must unlock.- Both
true→ server is online and serving normal traffic.
Rotation
When and why to rotate:
- Suspected key compromise.
- Periodic rotation per your security policy.
- Operator handover.
Procedure (web UI):
- Sign in as a superadmin.
- Settings → Security → Server encryption key.
- Enter the current key, the new key, and confirm the new key.
- Save the new key in your password manager BEFORE clicking Rotate.
- Click Rotate server key. The flow:
- Server validates the current key against the verifier.
- Reads every encrypted blob through the current key.
- Re-encrypts the verifier with the new key and installs the new key as live.
- Re-writes the secret blobs through the new key.
- The next server restart will require the NEW key.
CLI variant:
curl -X POST -H "Cookie: pika_session=$SESSION" \
-H "Content-Type: application/json" \
-d '{"current_key":"old","new_key":"new"}' \
https://localhost:8080/api/v1/key/rotateFailure modes during rotation
If step 4 (re-write secrets) fails after step 3 (verifier swap), the server is in a partial state: the verifier matches the new key but a settings row may still hold old-key ciphertext. Recovery:
- Retry rotation using the NEW key as both
current_keyand the re-typed new key. The verifier accepts the new key, and the re-write step runs again. This is safe: the settings wrapper re-extracts secrets every time, so re-running puts everything on the new key.
If the recovery rotation also fails:
- Restart the server, unlock with the new key, and inspect the settings row. Any secret slot that decrypts as garbage was lost in the half-rotation; restore from a recent backup taken under the new key (see Backups in Encryption).
Manual lock
You can lock the server without restarting it. Useful for:
- Rotation rehearsals on a non-production environment.
- "I'm stepping away from this terminal" if you're worried about a shoulder-surfer.
- Forcing every active user back through unlock when an operator leaves the company.
Web UI: Settings → Security → Server encryption key → Lock the server now.
CLI:
curl -X POST -H "Cookie: pika_session=$SESSION" \
https://localhost:8080/api/v1/key/lockAfter lock, every non-allowlisted request returns 503; the web UI's axios interceptor flips immediately to the unlock screen for all open browser tabs the next time they make any request.
Disaster scenarios
Lost key, no backup
Encrypted columns are unrecoverable. To restore service you must:
- Wipe the database (
PIKA_STORAGE_BW_PATHdirectory). - Start fresh. The Initialize flow will appear.
- Re-create users, mounts, hooks, externals from scratch.
User accounts and sessions are NOT in the encrypted set, but they live in the same Badger directory and a wipe loses them too.
Lost key, have a backup
- Locate a backup taken when you still had the key.
- Restore the backup into a fresh server.
- Unlock with the key that was active when the backup was taken.
- Once unlocked, rotate to a new key you control.
If you don't have the original key for the backup either, the backup is also unrecoverable — the export is the on-disk ciphertext as-is. Plan accordingly: backup-and-key-archive should live in the same secure store.
Operator handover
- Outgoing operator initiates rotation, picks the new key themselves, hands off through the org's normal credential- transfer process.
- Incoming operator confirms unlock works with the new key on the next restart cycle (e.g. roll one pod in a multi-replica deployment).
- Outgoing operator's password manager entry for the old key can be deleted.