czctl Admin Commands
This page extends the czctl command reference with full details for the admin and recovery commands. These commands mutate global state (users, master key, license, log level, retention), so they are documented separately so they are easy to audit and train on.
All examples assume you are in the Control Zero deployment directory
(where .env lives) and that czctl is on PATH. Every command that
talks to the database reads DATABASE_URL from the process
environment or from the local .env file.
czctl init
Interactive first-time setup wizard. Generates a fresh .env, creates
TLS certificates, and runs preflight checks.
Synopsis
czctl init [--quickstart]
Flags
--quickstart— zero-question setup. Useslocalhostas the domain, mints a 14-day trial license, generates self-signed certificates, and auto-generates every password / master key / JWT secret.
The global --yes / -y flag is honored and skips the "overwrite
.env?" confirmation.
Interactive flow (default)
When run without --quickstart, init prompts for:
- Domain (default
controlzero.local). - License key (leave blank for a trial).
- Secrets database password.
- Rate-limit cache password.
- Audit log store user and password.
- Master key passphrase (leave blank to auto-generate).
- JWT signing secret (leave blank to auto-generate).
At the end, it writes .env, generates TLS material under
config/certs/, and reports the next step (czctl preflight).
Version flag
czctl --version or czctl version prints the version, commit SHA,
and build date. Pair with --json for machine-parseable output.
czctl bootstrap-admin
Creates the first admin user for a fresh deployment. Designed for scripted, non-interactive use.
Synopsis
czctl bootstrap-admin --email <email> --password <password> --name <name>
Flags
| Flag | Required | Description |
|---|---|---|
--email | yes | Admin email address. |
--password | yes | Admin password, minimum 8 characters. |
--name | yes | Admin display name. |
Behavior
Inside a single database transaction, the command:
- Hashes the password with bcrypt (cost 12).
- Inserts a row into
users. - Inserts the new user into
platform_admins. - Upserts
system_initialized=trueintocz_config.
If a user with the given email already exists, the command aborts before any write with a non-zero exit.
Example
czctl bootstrap-admin \
--email ops@example.com \
--password 'a-strong-password' \
--name 'Ops Admin'
Security notes
- The password is read as a CLI flag and will appear in process listings
and shell history. Prefer piping via
sudo -Eor a one-shot shell that hasHISTCONTROL=ignorespaceset, then run the command with a leading space. DATABASE_URLmust be set in the environment. The command exits with a clear error if it is missing.
czctl reset-password
Resets a user's password by updating the bcrypt hash in users.
Synopsis
czctl reset-password --email <email> --new-password <password>
Flags
| Flag | Required | Description |
|---|---|---|
--email | yes | User email. |
--new-password | yes | New password, minimum 8 characters. |
Behavior
- Verifies the user exists.
- Hashes the new password with bcrypt (cost 12).
- Writes the new hash and updates
updated_at.
Example
czctl reset-password \
--email alice@example.com \
--new-password 'new-strong-password'
Security notes
- Same flag-exposure caveat as
bootstrap-admin. - Does not invalidate existing sessions. Revoke sessions manually if you are resetting in response to a compromise.
czctl rotate-master-key
Re-encrypts every secret in cz_secrets with a new master key
passphrase. Use this to rotate the master key periodically or in
response to a suspected compromise.
Synopsis
czctl rotate-master-key \
--old-passphrase <old> \
--new-passphrase <new> \
--confirm \
[--dry-run]
Flags
| Flag | Required | Description |
|---|---|---|
--old-passphrase | yes | Current master key passphrase. |
--new-passphrase | yes | New master key passphrase (must differ). |
--confirm | yes | Must be present to actually perform the rotation. Without it, the command prints a warning and exits. |
--dry-run | no | Decrypts every secret with the old key and re-encrypts in memory but does not commit. Use this to verify the old passphrase before a real rotation. |
Backup requirements
Before running this command you MUST:
- Stop the backend process (
docker compose stop backend). Leaving the backend running while the master key changes can corrupt newly written secrets. - Take a fresh backup (
czctl backup). If the rotation is interrupted, restoring from this backup is the safe rollback path.
The rotation itself runs in a single database transaction. If any step fails, no changes are committed.
What it does
- Reads the active salt from
cz_master_keys. - Derives the old key and validates decryption of every row in
cz_secrets. - Generates a new random salt and derives the new key.
- Re-encrypts each row with a fresh nonce and bumps
key_version. - Updates
cz_master_keys.saltandkey_hash. - Commits.
After a successful rotation
- Update
MASTER_KEY_PASSPHRASEin.envto the new passphrase. - Restart the backend:
docker compose restart backend. - Run
czctl postflightto confirm health.
Example
czctl rotate-master-key \
--old-passphrase 'old-passphrase' \
--new-passphrase 'new-stronger-passphrase' \
--confirm
czctl update-license <key>
Replaces CZ_LICENSE_KEY in .env and restarts the backend container
so the new license takes effect immediately.
Synopsis
czctl update-license <license-key>
Behavior
- Validates the key starts with
czs_. - Updates or appends
CZ_LICENSE_KEY=<key>in.env(file permissions set to0600). - Runs
docker compose restart backend.
Example
czctl update-license czs_abc123...
czctl set-log-level <level>
Sets the application log level for the running backend. The backend
polls cz_config and picks up the new level within 60 seconds; no
restart required.
Valid levels
trace, debug, info, warn, error (case-insensitive).
Example
czctl set-log-level debug
Behavior
Upserts log_level in cz_config with updated_by=czctl. Everything
is audited through the cz_config.updated_at field.
czctl set-log-retention <days>
Sets the number of days to keep audit logs before automatic trimming. Must be a positive integer.
Example
czctl set-log-retention 90
Behavior
- Upserts
audit_retention_daysincz_config. - The backend's retention sweeper applies the new value on its next
run and trims rows older than
<days>from the audit store. - Lowering the retention window triggers an immediate prune on the next sweep; raising it keeps everything already retained.
czctl support-bundle
Collects a sanitized diagnostic archive for support escalations. All passwords, license keys, API keys, session tokens, and connection strings containing credentials are redacted before the archive is written.
Synopsis
czctl support-bundle [--hours 48]
Flags
| Flag | Default | Description |
|---|---|---|
--hours | 48 | Hours of logs to include. |
What is collected
- Host system info (OS, kernel,
docker --version,docker compose ps). - Service logs for the configured time window.
- Container status.
- Health-check output.
- Database statistics (row counts, last migration).
What is redacted
The following patterns are replaced with <REDACTED> before inclusion:
PASSWORD=…,DB_PASSWORD=…,CZ_SIGNING_SECRET=…,SECRET_KEY=….CZ_LICENSE_KEY=…,LICENSE_KEY=….- API keys matching
cz_live_…orcz_test_…. - Session keys matching
czs_…. Bearer …tokens.- Credentials embedded in cache and database connection strings.
Output
Writes cz-support-<timestamp>.tar.gz to the current directory. Attach
this file when opening a support ticket.
czctl generate-ca
Generates a self-signed certificate authority and server certificate for TLS termination. Use this for local / air-gapped installs where Let's Encrypt cannot reach the host.
Synopsis
czctl generate-ca \
[--output config/certs] \
[--cn "Control Zero CA"] \
[--days 365] \
[--domain localhost]
Flags
| Flag | Default | Description |
|---|---|---|
--output | config/certs | Output directory. Created if missing. |
--cn | Control Zero CA | Common Name for the CA certificate. |
--days | 365 | Validity period in days. |
--domain | localhost | Domain added as Subject Alternative Name on the server cert. |
Output files
ca.pem— CA certificate.ca-key.pem— CA private key. Keep offline after use.cert.pem— server certificate (signed by the CA, SAN =--domain).key.pem— server private key.
When to use
czctl initcalls this automatically in quickstart mode forlocalhost.- Air-gapped and offline installs that cannot use Let's Encrypt.
- Internal QA / staging where you want a local root you control.
For production public hostnames, prefer a real CA. See SSL proxy for options.