Skip to content
All docs

Docs

Key rotation

Replacing ENCRYPTION_KEY without downtime, and without losing a secret.

ENCRYPTION_KEY is what makes stored env vars, database passwords, registry and git credentials, S3 keys and notification configs readable. Losing it makes them unrecoverable, so it is worth rotating on a schedule and after anyone who had it leaves.

ENCRYPTION_KEYS is the comma-separated form: the first entry encrypts, every entry can decrypt. That overlap is what makes a rotation possible with the panel running.

The runbook

sh
1# 1. generate the new key 2openssl rand -hex 32 3 4# 2. /etc/nixploy/.env — NEW key first, current key second 5ENCRYPTION_KEYS=<new>,<current> 6 7# 3. restart the panel so it reads both 8docker service update --force nixploy 9 10# 4. rewrite every secret column with the new key 11docker exec nixploy pnpm -F @nixploy/server nixploy:rotate-key 12 13# 5. /etc/nixploy/.env — drop the old key, restart again 14ENCRYPTION_KEYS=<new>

Flags worth knowing

  • --dry-run — report what would change and write nothing
  • --batch-size=500 — rows per transaction
  • --table=notification — one table only
  • --skip-undecryptable — leave rows no configured key can read, for the case where a key really was lost

The script discovers the columns from the schema, so a new secret column needs no change to it. Each batch is one transaction, and a row that no configured key can authenticate aborts the run and names the table, column and row — a rotation never half-writes.

Passphrases and formats

A key may also be a passphrase of 32 characters or more. Those are stretched with scrypt and written with a version prefix; 64-character hex keys are used directly. Both forms stay readable forever, so moving a passphrase install onto a hex key is just another rotation.

Before you start

  • Take an instance backup first — the rotation rewrites every secret column
  • Keep the old key until step 5 has completed successfully; a restore from a dump taken before the rotation still needs it
  • /etc/nixploy/.env is deliberately excluded from instance backups, so store both keys somewhere the backup reader cannot reach
  • Treat a lost key as a migration, not a config change: without it every credential has to be re-entered by hand

Also see the repository guides under docs/ · REST API reference

Rent the box. Keep the rest.

One command, three services, and the first account is yours.