cpk Command Reference

cpk is the installer and lifecycle binary shipped inside the CloudPeek bundle. Run commands from inside the cloudpeek/ directory: cpk resolves the compose file, image archive and supporting directories relative to its working directory, and stops immediately if it cannot find them.

uninstall is a partial exception. Its Docker cleanup works from anywhere, because it finds containers, volumes and images by label. Its second step, the offer to delete the generated secrets, only ever looks at the directory you ran it in, so running it from elsewhere silently skips that prompt. There is no reason not to be consistent and run everything from the install directory.

CommandWhat it does
./cpk installRun the installer. Refuses to run over an existing install.
./cpk configureUpdate safe operational settings in place while preserving data, public identity and durable credentials.
./cpk update --new PATHUpgrade in-place from a newer installer tarball (-y to skip the prompt).
./cpk adduserAdd a user from the host, interactively.
./cpk uninstallRemove the containers, volumes, network and images, then offer to remove the generated secrets. Destroys your data.
./cpk exportExport the current instance (add --save-data to include volumes).
./cpk importImport and start a cluster from a previous export.
./cpk verifyRun the post-install healthcheck (needs Chrome + chromedriver). Not read-only by default.
./cpk diagnosticsReport what is wrong with a running install and write a redacted support bundle. Strictly read-only.
./cpk renew-certReplace the TLS certificate and restart the proxy.
./cpk sync-zitadel-rolesRepair the identity provider's role catalogue, when update reports its automatic sync did not run.
./cpk migration --last-version VERSIONApply the one-time reconciliation steps introduced since VERSION. Normally run for you by update.
./cpk --help (-h)Show full usage help.
./cpk --version (-v)Show the installed version.
./cpk --verboseDetailed logging.

Command-specific flags

FlagApplies toWhat it does
--forceinstallInstall even if this directory already holds an install. Breaks the existing instance.
--new PATHupdateThe newer installer tarball to upgrade from. Required. A relative path is resolved against the current directory.
-y, --yesupdate, configureSkip the ordinary final confirmation. Configure still asks its settings questions, and aborts rather than continuing if a dependency is unreachable.
--save-dataexportInclude the data volumes in the export. Stops the containers for the duration.
--keep-rate-limitverifyLeave .secrets/api.env and the API container untouched. Use on production installs.
--regenerateverifyRebuild .secrets/tests.env from api.env.
--cert PATHrenew-certThe replacement certificate, PEM. Prompts if omitted.
--key PATHrenew-certThe replacement private key, PEM. Prompts if omitted.
--last-version VERSIONmigrationThe version the install was on before the update. Required, and validated, so a typo gets a one-line error rather than a stack trace.
--http-proxy URLinstallOutbound HTTP proxy. Also settable as http_proxy/HTTP_PROXY; the flag wins.
--https-proxy URLinstallOutbound HTTPS proxy. Also settable as https_proxy/HTTPS_PROXY.
--no-proxy-extra LISTinstallComma-separated hosts to add to the proxy bypass list. Additive: it never shrinks the built-in list.
--ca-cert PATHinstallCorporate CA bundle to trust. Must be a readable file, or the install fails.
--since DURATIONdiagnosticsLog window, e.g. 30m, 6h, 2d. Default 24h, maximum 48h.
--max-log-lines NdiagnosticsCap log collection per container. Default 100000.
--output-dir DIRdiagnosticsWhere to write the bundle. Default ./cloudpeek_<hostname>_<ddmmyy_hhmm>. Must be empty or new.
--no-bundlediagnosticsReport on screen only, writing nothing to disk.
--no-archivediagnosticsLeave the bundle directory untarred.
Note

--verbose raises the log level globally. configure emits value-free validation and health milestones; install, update, import, migration and sync-zitadel-roles provide their command-specific diagnostics. It has no effect on uninstall, export, adduser or verify. diagnostics uses it to also show the checks that passed, not just the problems.

Flags are parsed from one shared table, so any flag is accepted on any command and simply ignored where it does not apply: ./cpk uninstall --cert foo runs an ordinary uninstall. An unrecognised flag is a different matter and fails the parse before anything runs.

Docker requirements

Most commands check for Docker before doing anything, and require Docker Engine 29 or newer. adduser, verify and sync-zitadel-roles skip that check deliberately, because they talk to an already-running stack rather than managing it.

diagnostics skips it for a different reason. It does need Docker, but the standard check refuses to run on a daemon below the minimum, and diagnostics has to work on hosts that are already broken. So it runs a softer preflight of its own: an unsupported daemon is reported as a finding and the run continues. It stops only when the docker binary is missing or the daemon cannot be reached at all.

What each command asks before it acts

Several commands are interactive, and a couple ask a second question well after the one you were expecting. This is the full list of confirmation points.

CommandPrompt
installHost, scheme, TLS source, admin account and per-service settings.
configurePer settings group, then a final preview and Apply these changes?.
updateA single Continue? warning, skipped by -y.
uninstallContinue?, then, after the Docker cleanup, Also remove the generated secrets?.
importRestore volume data?, but only when the export contains volume archives.
verifyNothing, unless no default AI provider is configured, in which case it asks for one.
diagnosticsNothing. It never prompts and never changes the install.
renew-certCertificate and key paths, unless both were passed as flags.
adduserEmail, password, names and permissions. See below.
Warning

uninstall asks twice. The first prompt covers containers, volumes, the network and images. The second, which appears only after that work is done, offers to delete the generated secrets (compose.env, api.env, worker.env, frontend.env, tests.env and the Zitadel master key). Declining leaves them in place, which will make the next ./cpk install refuse to run unless you pass --force. Operator-supplied certificates in .secrets/tls are never deleted either way.

Important

./cpk verify is not read-only. By default it writes RATE_LIMIT__ENABLED=false and CLOUDPEEK_E2E_FLAGS=1 into .secrets/api.env and recreates the API container, restoring the file when it finishes. The test suite's request bursts would otherwise trip the rate limiter. On a production install, pass --keep-rate-limit so nothing is touched, accepting that the feature-flag scenarios will fail unless CLOUDPEEK_E2E_FLAGS=1 is already set.

Collecting a support bundle

./cpk diagnostics is what to run when something is wrong and you want CloudPeek support to look at it. It inspects the running stack, prints what it finds, and writes a bundle you can send on.

cd cloudpeek
./cpk diagnostics

It is strictly read-only. It never starts, stops or reconfigures anything, never prompts, and writes nothing outside the output directory. It is safe to run on a production install, and safe to run repeatedly.

It also works on a broken one, which is rather the point. If the stack is completely down, the run still completes and still produces a bundle: it falls back from the compose configuration to Docker labels to container name patterns, and reports each missing piece as a finding.

What it checks

Nine checks run in order, each reporting its own findings:

CheckLooks at
Host informationKernel, Docker version and storage driver, disk and memory
Configuration keysWhich expected keys are present in .secrets/*.env, by name
Container stateStatus, restart counts, exit codes, out-of-memory kills, health
Expected servicesServices declared in compose that have no container, or the wrong state
Version driftWhether each running image matches the installed cpk version
TLSCertificate subject, validity dates and expiry warnings
Container logsError lines in the log window, grouped by frequency
Service healthAPI, frontend and MCP health endpoints, probed from inside the network
DependenciesRedis, Postgres, ChromaDB and Neo4j reachability, plus queue depths

Problems are printed as you go, then summarised: either Diagnostics found no problems. or Diagnostics found N error(s) and M warning(s). Add --verbose to see the passing checks too.

What is in the bundle, and what is redacted

Everything written to the bundle, and everything printed to the terminal, passes through a single redaction filter. It masks credential-shaped text: passwords embedded in connection strings, environment variables and JSON fields whose name looks secret (PASSWORD, SECRET, TOKEN, API_KEY, _PAT and similar), secrets in URL query strings including AWS presigned parameters, and Authorization: Bearer/Basic values.

Three things are worth stating plainly:

  • Your TLS private key cannot appear in a bundle. The certificate check reads only cert.pem, to report its subject and dates. key.pem is never opened.
  • The values in .secrets/*.env are never collected. The configuration check works purely from key names, so it can tell you a key is missing without ever reading what it is set to.
  • No file is copied verbatim. .secrets/, compose.yml and Docker's own configuration are never included. The bundle contains only the command output described above.
Warning

Redaction masks credentials, not content. Application logs can legitimately contain incident data, hostnames, IP addresses, user email addresses and model payloads, and none of that is masked. The command says so when it finishes, and it is worth acting on: review a bundle before you send it. If it contains something you cannot share, delete that file from the bundle directory and re-archive it, or re-run with --no-bundle and share only the on-screen summary.

Masking is also applied line by line, so a credential split across two lines is not caught.

Narrowing what it collects

./cpk diagnostics --since 2h --max-log-lines 5000

--since accepts 30m, 6h, 2d and so on, defaulting to 24h and capped at 48h. An invalid or zero value is rejected before anything is collected. Narrowing the window is the usual way to keep a bundle small when you already know roughly when the problem started.

Use --no-bundle to see the findings without writing anything to disk, and --no-archive to leave the bundle as a directory rather than a .tar.gz when you want to inspect or edit it first.

Sending it

By default the bundle lands in ./cloudpeek_<host>_<timestamp>/ and is archived alongside it as .tar.gz. Send that archive to your CloudPeek support contact.

--output-dir must point at a new or empty directory. This is deliberate: the bundle is archived whole, so an existing directory would sweep unrelated files into something you are about to email.

Exit codes

Most commands exit 0 on success and 1 on failure. Three behaviours are worth knowing before you put cpk in a script.

verify never returns a non-zero exit code. It catches everything, and a failing suite is reported as a warning rather than an error. Do not gate a pipeline on its exit status; read its output instead.

diagnostics findings never change the exit code either. It exits 0 even when it reports errors, on the same reasoning: finding problems is the job, not a failure to do it. It exits 1 only for an invalid flag value, a missing docker binary or an unreachable Docker daemon. If it cannot write the bundle, it warns and still exits 0.

update fails closed when it cannot ask. Without -y, its confirmation prompt aborts rather than hanging if there is nothing on standard input, so an unattended run that forgets -y stops safely instead of blocking forever.

Recovering a partial update

update runs two follow-up steps that are allowed to fail without failing the upgrade itself, because neither affects whether the new version runs. If either warns, run the command it names.

Warning from updateFix
The Zitadel role sync did not run./cpk sync-zitadel-roles
The migration step did not run./cpk migration --last-version VERSION, with the version it prints

Both are safe to re-run. migration applies only the steps introduced between the version you give it and the installed version, so running it twice does nothing the second time, and running it with a version at or above the current one reports that there is nothing to do.

Where each command is covered

adduser creates an account from the host, without going through the web interface. It is the quickest way to add the second account to a fresh instance; day to day, manage users in the app instead — see Admin & Settings.

It asks, in order: email, password and confirmation (same complexity rules as the installer, and the same abort on a mismatch), first name and last name (both defaulting to User), then Grant all permissions to this user? y/n. Answering y is the quick path. Anything else walks through each resource in turn, offering all, none or pick, where pick asks per action — thorough, but long.

If the account is created but the permissions cannot be granted, adduser deletes the new user rather than leaving one behind with no access. In the rare case that the cleanup also fails, it prints the user id and email to remove by hand before retrying.

It needs .secrets/api.env and .secrets/compose.env, so it only works on a host where the install has already run.

© 2026 CloudPeek. Agentic AI for high-consequence security operations.