Installing CloudPeek
This page assumes you have already checked the host requirements and verified the bundle signature, as described in Prerequisites.
Extract the bundle
Once the signature has been verified, extract the tarball:
tar -xzf cloudpeek-installer-v0.8.0-linux-x86_64.tar.gz
This creates a cloudpeek/ directory containing the cpk installer binary, the healthcheck binary, the Docker image archive, the compose file, a copy of these instructions, and the supporting directories the installer depends on (entrypoint, features, installation, opa, runbooks, terraform, traefik and zitadel).
Keep the directory intact. Before installing, cpk checks those entries are present and aborts with Install aborted: N required entries missing if any are not.
That preflight covers the compose file, the two binaries and the eight directories — but not cloudpeek-images.tar.gz. A missing or truncated image archive passes the check and fails later, while the install is loading images.
Run the installer
cpk looks for the compose file, Docker image archive, and supporting directories relative to its current working directory. You must cd into cloudpeek/ before running it — running it from anywhere else will stop immediately and report the files as missing.
cd cloudpeek
./cpk install
It first checks your Docker version and that the bundle's supporting files are present, then asks the following, in this order.
install refuses to run over an existing install. If it finds .secrets/compose.env or .secrets/api.env from a previous run it stops, because regenerating those credentials would leave them out of step with the existing data volumes. Use ./cpk configure to change supported operational settings without deleting data, ./cpk update to upgrade, or ./cpk uninstall to start over. ./cpk install --force overrides the refusal and will break an existing instance.
Because the guard only looks for those generated files, an install abandoned at a prompt — or aborted by a password mismatch — leaves nothing behind and can simply be retried.
1. Host/Domain (required)
The address users will reach CloudPeek on, for example app.cloudpeek.ai, an IP, or localhost. A full URL is accepted, and a port in it will be used.
2. Use https? (y/n)
Answer y unless the host you gave above is localhost or 127.0.0.1. Only y selects HTTPS — any other answer, including a typo, selects HTTP. The installer warns, but carries on rather than re-asking.
On any other hostname or IP, answering n produces an install you cannot log in to. The identity provider issues session cookies marked secure-only, which browsers reject over plain HTTP. Browsers make an exception for localhost, which is why HTTP is only safe to choose there.
Answering n skips the next prompt. An HTTP install is published on port 8080 by default, so you reach it at http://<host>:8080 — http://localhost:8080 for the one host where HTTP is a safe choice.
3. TLS certificate source
Enter one of:
| Option | Source | What it needs |
|---|---|---|
1 | self-signed (the default) | Nothing; browsers will warn on first visit |
2 | byo | Your own certificate and key file |
Self-signed generates an RSA-4096 certificate valid for 825 days. Anything other than 2 selects it.
Bring your own asks for the certificate path, then the key path. A path that does not exist is re-asked indefinitely, so there is no way to skip past a typo.
The installer does not obtain certificates from a certificate authority itself — there is no Let's Encrypt or ACME option. See Using a CA-issued certificate below for how to serve a publicly trusted certificate.
4. Admin email (required)
The account you will first log in as.
5. Admin password (required), then Confirm admin password
Must contain a lowercase letter, an uppercase letter, a number, and a special character. The password prompt re-asks until those rules are met.
The confirmation does not re-ask. If the two entries differ, the installer prints Passwords don't match and exits; you have to run ./cpk install again from the start.
6. Admin first name and last name
Both optional, defaulting to Admin and User. Press Enter to accept.
7. Keep default <service> settings y/n
Asked once per service: Postgres, Redis, MinIO, Neo4j, ChromaDB, OPA, Traefik, Zitadel, API, frontend, and memory. Answer y to each unless you need to change hosts, ports or credentials. Answering anything else walks you through that service's individual settings, each showing its default.
The check is for exactly y — typing yes counts as "no" and drops you into the full list of settings for that service. A blank answer re-asks rather than accepting the default.
MinIO, Neo4j, ChromaDB and memory open with an enabled y/n question. Answering anything but y there disables the service and skips the rest of its settings.
What happens next
From there the installer needs no further input: it loads the bundled Docker images, starts the identity provider, creates your admin account, and brings up the rest of the stack.
Network access: unless you were supplied an air-gapped bundle, the installer downloads any third-party images that aren't already on the host. An air-gapped bundle contains every image up front and installs with no network access. If you are unsure which you received, ask your CloudPeek contact before installing on an isolated host. See Deployment Options for more on air-gapped operation.
When it finishes, the installer prints the URL to log in at.
CloudPeek is not usable until you configure an LLM provider. Log in and visit /admin/settings to set up your first one — see Configure an AI model provider for the walkthrough.
Using a CA-issued certificate
The installer will not fetch a certificate from a certificate authority for you. To serve a publicly trusted certificate, obtain one out of band and import it with the byo option.
With Let's Encrypt's certbot, on a host whose DNS already points at it and with port 80 free:
sudo certbot certonly --standalone -d your.domain
That writes fullchain.pem and privkey.pem under /etc/letsencrypt/live/your.domain/. Give those two paths to the byo prompts. Any other CA works the same way: a PEM certificate including the intermediate chain, plus its unencrypted private key.
The installer checks the pair before importing it. A certificate and key that don't match, an expired certificate, an unreadable PEM, an encrypted private key, or a combined cert+key file (including the same file given for both paths) are all rejected and re-asked, rather than producing an install that only fails once Traefik starts. Three findings warn without blocking: a SAN that doesn't cover the install host, an expiry within 30 days, and a notBefore date still in the future are printed, and the import continues.
Renewal is yours to schedule. Nothing tracks expiry for you. Rotate the certificate before it runs out with ./cpk renew-cert.
Rotating the certificate
cd cloudpeek
./cpk renew-cert --cert /path/to/fullchain.pem --key /path/to/privkey.pem
This validates the new pair, backs up the current one to timestamped .bak files in .secrets/tls/, writes the replacement, and restarts Traefik. The restart is the part you can't skip — Traefik reads the certificate files only at startup, so a hand-copied certificate is ignored until the container cycles. Omit either flag to be prompted for it.
The restore command is printed when it finishes. To automate renewals, call it from a certbot deploy hook:
#!/bin/sh
# /etc/letsencrypt/renewal-hooks/deploy/cloudpeek.sh
set -e
cd /opt/cloudpeek
./cpk renew-cert --cert "$RENEWED_LINEAGE/fullchain.pem" \
--key "$RENEWED_LINEAGE/privkey.pem"
Do not pass a combined cert+key PEM as --cert. It is rejected on purpose: that file would be written where Traefik serves it publicly, disclosing your private key. Split it first.
If the restart doesn't come back healthy the new certificate is left in place, not auto-reverted — docker compose --wait reports a non-zero exit for a merely-slow start as well as a real failure, so reverting automatically would silently undo correct rotations. Use the printed restore command if you need to go back.
Optional: verify the install
If Chrome and chromedriver are on PATH, you can run a post-install smoke check:
./cpk verify
verify is not read-only. By default it rewrites .secrets/api.env to turn the API rate limiter off and the end-to-end feature-flag anchor on, recreates the cloudpeek-api container, runs the suite, then restores the file. On a production install, use ./cpk verify --keep-rate-limit to leave api.env and the container alone.
If no model provider is configured yet, verify also runs a short wizard asking which provider to use and for its credentials, and saves them to .secrets/tests.env. Add --regenerate to rebuild that file from api.env.
Reconfiguring an existing install
install refuses to run twice, but most operational settings can be changed afterwards without touching your data:
cd cloudpeek
./cpk configure
Like the other commands it must run from inside cloudpeek/. It reads compose.yml and the compose.env, api.env, worker.env and frontend.env files in .secrets/, and stops if any of them is missing. Docker has to be available too: the proposed configuration is handed to docker compose config for checking before anything is written.
What configure can change
Settings are grouped, and each group is offered in turn with Change <group> settings? y/N:
| Group | Covers |
|---|---|
| API | API log level |
| Data connections | Database pool size and max overflow, Redis URL, MinIO enabled/endpoint/TLS |
| Authorization | OPA URL, timeout and policy path |
| Memory | AI memory on/off, embedding model and dimensions, LLM timeout, graph on/off, the memory ChromaDB and Neo4j URLs, and the ChromaDB and Neo4j client settings |
| Proxy | Traefik dashboard, log level and access log |
| Observability | OpenTelemetry enabled, endpoint, and headers as a JSON object such as {"Authorization":"Bearer token"} |
Answer anything other than y and the entire group is skipped, so a blank answer moves on rather than re-asking, and — as during install — typing yes counts as "no".
Inside a group each setting is asked in turn, showing what it accepts on a Values: line — the log-level words, a number's range, a URL's schemes — above its current value. Free-text settings such as the OPA policy path have no Values: line. Pressing Enter keeps the current value, so you can walk through a group and change only the one setting you came for. A value that fails validation is reported and re-asked rather than accepted.
Only settings your .secrets files already contain are offered. configure changes existing values; it does not introduce a setting the install has never had.
What it will not change
configure deliberately leaves alone everything that would put an existing instance out of step with its own data: application encryption keys, database and managed-service credentials, the Zitadel identity, the public host and HTTPS choice, and TLS material. It prints that list before asking to apply. Persistent volumes are never deleted.
There is no in-place path through configure for the host, the HTTPS choice or the admin account. Replace the certificate with ./cpk renew-cert.
Preview, confirm, apply
After the questions, configure validates the whole proposed configuration, then prints the changes, the containers it expects to restart, and a line confirming no volumes are affected. Answer y to Apply these changes? y/N and it recreates only those containers, waiting for each to report healthy; if the API was one of them, its health endpoint is checked as well.
Answering n to every group, or leaving every value blank, normally prints No configuration changes selected. and exits having written nothing. The exception is the worker memory sync described below, which configure adds on its own — if that fires, the run continues to the preview and apply even though you asked for no changes.
Sensitive values — URLs and endpoints that can carry credentials — are masked as ******** at the prompt and shown as <redacted> in the preview. Have the value you intend to set to hand; the screen will not remind you what the current one is.
-y skips only the final Apply these changes? confirmation. It does not answer the per-group and per-setting questions, so ./cpk configure -y is not an unattended command. It also does not auto-approve an unreachable dependency: with -y, that case aborts with the names of what could not be reached, changing nothing, rather than waiting on a prompt no script can answer.
Unreachable dependencies
When you change a Redis, OPA, ChromaDB, Neo4j, MinIO or OpenTelemetry address, configure tries to reach it before applying, and asks Apply despite unreachable dependencies? y/N if it cannot. Under -y there is no prompt: the run aborts and names what it could not reach.
That probe runs from the host, not from inside the container network. An address that only resolves between containers — http://opa:8181, say — is reported unreachable even though it is correct, and answering y is the right call. Treat the warning as a prompt to re-read the address, not as proof it is wrong.
If something goes wrong
Changes are staged in .secrets/.configure-transaction/ before being written. If the new configuration fails to come up, configure puts the previous files back, restarts the affected services again, and reports Configuration was rolled back — the install is left as it was.
If that rollback cannot itself be confirmed, the transaction directory is kept and its path printed. Leave it there: the next ./cpk configure finds it, restores the previous configuration and reconciles the services before it does anything else.
Do not hand-edit .secrets/*.env while a transaction directory exists. Recovery checks the live files against what it staged and refuses to run if they changed underneath it, leaving you to restore .secrets/.configure-transaction/backups/ by hand.
Every finished run — applied or rolled back — appends a line to .secrets/configure-audit.log recording the timestamp, which settings changed and which services were restarted. The values themselves are not logged. Add --verbose for validation and health milestones as it runs; those are value-free too.
Two messages worth recognising. <setting> has conflicting values in the current configuration means the same setting is set two different ways across the .secrets files, usually after a hand-edit — make them match before running configure. And a change you did not ask for, Worker memory configuration: incomplete -> synchronised, is configure copying memory settings the API already has into worker.env, where an older install may be missing them. The preview explains it in place. It is safe to apply, but it cannot be declined, and it restarts the worker and scheduler.
Related
- Quickstart: configure a model provider and connect your first tool.
- Admin & Settings: users, tenants and the settings hub.
- Updating CloudPeek: upgrading in place from a newer bundle.
- Deployment Options: how this fits cloud, on-prem and air-gapped.