Skip to main content

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. Uses localhost as 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:

  1. Domain (default controlzero.local).
  2. License key (leave blank for a trial).
  3. Secrets database password.
  4. Rate-limit cache password.
  5. Audit log store user and password.
  6. Master key passphrase (leave blank to auto-generate).
  7. 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

FlagRequiredDescription
--emailyesAdmin email address.
--passwordyesAdmin password, minimum 8 characters.
--nameyesAdmin display name.

Behavior

Inside a single database transaction, the command:

  1. Hashes the password with bcrypt (cost 12).
  2. Inserts a row into users.
  3. Inserts the new user into platform_admins.
  4. Upserts system_initialized=true into cz_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 -E or a one-shot shell that has HISTCONTROL=ignorespace set, then run the command with a leading space.
  • DATABASE_URL must 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

FlagRequiredDescription
--emailyesUser email.
--new-passwordyesNew password, minimum 8 characters.

Behavior

  1. Verifies the user exists.
  2. Hashes the new password with bcrypt (cost 12).
  3. 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

FlagRequiredDescription
--old-passphraseyesCurrent master key passphrase.
--new-passphraseyesNew master key passphrase (must differ).
--confirmyesMust be present to actually perform the rotation. Without it, the command prints a warning and exits.
--dry-runnoDecrypts 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:

  1. Stop the backend process (docker compose stop backend). Leaving the backend running while the master key changes can corrupt newly written secrets.
  2. 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

  1. Reads the active salt from cz_master_keys.
  2. Derives the old key and validates decryption of every row in cz_secrets.
  3. Generates a new random salt and derives the new key.
  4. Re-encrypts each row with a fresh nonce and bumps key_version.
  5. Updates cz_master_keys.salt and key_hash.
  6. Commits.

After a successful rotation

  1. Update MASTER_KEY_PASSPHRASE in .env to the new passphrase.
  2. Restart the backend: docker compose restart backend.
  3. Run czctl postflight to 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

  1. Validates the key starts with czs_.
  2. Updates or appends CZ_LICENSE_KEY=<key> in .env (file permissions set to 0600).
  3. 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_days in cz_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

FlagDefaultDescription
--hours48Hours 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_… or cz_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

FlagDefaultDescription
--outputconfig/certsOutput directory. Created if missing.
--cnControl Zero CACommon Name for the CA certificate.
--days365Validity period in days.
--domainlocalhostDomain 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 init calls this automatically in quickstart mode for localhost.
  • 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.