Quick Start — Single Node
A working CBOM Secure on one host, from nothing, in about half an hour. This is the fastest supported path: every service in containers on a single machine, one TLS certificate, one administrator account.
Use this for an evaluation, a lab, or the first node of a deployment you will grow later. For a production estate read Sizing, Topologies and Ports and Firewall first — the shape you start with is harder to change than the size.
Before you start
| Requirement | Minimum |
|---|---|
| CPU | 8 cores |
| Memory | 32 GB |
| Disk | 200 GB SSD |
| Operating system | A current 64-bit Linux with a modern kernel |
| Software | Docker Engine with the Compose plugin |
| Network | Outbound HTTPS, and port 443 reachable by the people who will use it |
A smaller host will start and will serve a demonstration. It will not survive a scan of a real estate — see Sizing for the figures.
You also need the repository, including its submodules:
git clone --recurse-submodules <repository-url> cbom
cd cbom
A clone without --recurse-submodules is missing the sensors, and the discovery service starts with nothing to run. If you already cloned without them: git submodule update --init --recursive.
Step 1 — Create the TLS certificate
The reverse proxy and the identity provider both read a certificate from certs/ next to the compose file. For an evaluation a self-signed certificate is fine; for anything a browser other than yours will visit, use one your organisation trusts.
mkdir -p certs
openssl req -x509 -nodes -days 365 \
-newkey rsa:2048 \
-keyout certs/key.pem \
-out certs/cert.pem \
-subj "/CN=cbom.example.com" \
-addext "subjectAltName=DNS:cbom.example.com,DNS:localhost,IP:127.0.0.1"
Use the name people will actually type. A certificate issued for localhost and then reached by address produces a warning on every visit, and sign-in redirects are checked against the name — so the mismatch is not only cosmetic.
Step 2 — Fill in the environment file
cp .env.example .env
Open .env and set these before starting anything. Every one of them ships as a placeholder.
| Variable | What to set it to |
|---|---|
MONGO_ROOT_PASSWORD | A long random string |
RABBITMQ_PASSWORD | A long random string — the broker credential the agents use |
RABBITMQ_MGMT_PASSWORD | A different long random string |
FLASK_SECRET_KEY | 64 random characters |
DEPLOYMENT_SECRET_KEY | A Fernet key — see below |
KEYCLOAK_CLIENT_SECRET | A long random string |
KC_ADMIN_PASSWORD | A long random string |
KEYCLOAK_SA_PASSWORD | A long random string |
PUBLIC_BASE_URL | https://cbom.example.com — the name on your certificate |
Generate the values:
# Fernet key for DEPLOYMENT_SECRET_KEY
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
# Everything else
openssl rand -base64 48
DEPLOYMENT_SECRET_KEY must be a valid Fernet key, not just a random string. It encrypts every stored target credential. A value that is not a well-formed Fernet key fails when the first credential is saved, not at startup — so the failure arrives later, out of context.
Keep the two broker passwords different. RABBITMQ_PASSWORD is the credential every deployed agent carries in its own configuration, in plaintext, on hosts you do not control — and it carries the administrator tag. RABBITMQ_MGMT_PASSWORD is the management portal login. Reusing one value for both means recovering any agent's config file hands over the broker's management interface.
Then set the addresses to the name on your certificate:
PUBLIC_BASE_URL=https://cbom.example.com
CBOM_SERVER_URL=https://cbom.example.com/cbomsrv
FRONTEND_URL=https://cbom.example.com
VITE_BACKEND_URL=https://cbom.example.com/cbomsrv/api/v1
COLLECTOR_SERVER_URL=https://cbom.example.com/collector
KEYCLOAK_PUBLIC_URL=https://cbom.example.com/auth/
Do not leave these as localhost on a host that will deploy agents. Two of these addresses are resolved on the target host, not on the platform — so a loopback value names the agent rather than CBOM. The deployment reports success, the scan runs, and the results go nowhere. The server warns at startup when either resolves to loopback; read that warning.
Step 3 — Create the first administrator
Still in .env:
INITIAL_ADMIN_MODE=create
INITIAL_ADMIN_USERNAME=admin
[email protected]
INITIAL_ADMIN_FIRST_NAME=Platform
INITIAL_ADMIN_LAST_NAME=Administrator
INITIAL_ADMIN_PASSWORD=<a strong password>
A one-shot container creates this account in both the identity provider and the platform once the backend is healthy, then exits. It is safe to re-run and does nothing if an administrator already exists.
Leave INITIAL_ADMIN_MODE=skip if you intend to sign in through SSO and promote that account afterwards instead.
Step 4 — Start it
docker compose up --build -d
The first run builds the images and takes a while. Services start in dependency order and nothing starts before what it depends on reports healthy, so a slow start is normal and a stalled one is informative.
Watch it come up:
docker compose ps
docker compose logs -f cbom-server
Wait until docker compose ps shows the long-running services healthy and the one-shot containers — the database seed, the broker seed, the administrator bootstrap — exited with status 0.
Step 5 — Sign in
Open https://cbom.example.com and sign in with the administrator account from step 3.
| What | Where |
|---|---|
| Console | https://cbom.example.com/ |
| Help | https://cbom.example.com/helpdocs/index.html |
| API docs | https://cbom.example.com/cbomsrv/docs |
| Telemetry dashboards | https://cbom.example.com/grafana/ |
| Broker management | https://cbom.example.com/rabbitmq/ |
Only port 443 is published to the host. Everything else talks on the internal container network, which is why there is one firewall rule to open rather than a dozen.
Step 6 — Prove it works
Run a scan that needs no credentials and no agent, so a failure can only be the platform.
Add a host. Discovery → Host → Add. Any reachable name will do.
Create a template. Discovery → Template → Add, with the HTTPS sensor and one endpoint you know serves TLS.
Create a task. Discovery → Tasks → Networked Deployments, binding the template to the host.
Run it, and watch the deployment history.
Check the inventory. Crypto Inventory → Certificate should show the endpoint's certificate.
If the certificate appears, discovery, ingestion, deduplication and the dashboards are all working. That is the whole data path in one test.
What to do next
| Next | Why |
|---|---|
| Replace the self-signed certificate | See Certificates. A browser warning trains people to click through warnings. |
| Review Ports and Firewall | Open what you will use; the default exposes one port. |
| Set up SSO | See OIDC and Entra ID, or SAML 2.0 SSO. |
| Review Roles and Permissions | The default role map permits what the API permits today. Narrow it. |
| Configure backups | See Backup and Recovery and Database Administration. The restore is the part to exercise. |
| Plan the growth path | See High Availability Runbooks before you need it. |
If it does not start
A service restarts in a loop. docker compose logs <service>. A placeholder left in .env is the most common cause, and the message usually names the setting.
The database seed container exits non-zero. It could not reach MongoDB, or MongoDB rejected the credentials. Check MONGO_ROOT_USER and MONGO_ROOT_PASSWORD, then docker compose logs mongodb.
Sign-in redirects to a certificate warning or an unreachable address. KEYCLOAK_PUBLIC_URL or PUBLIC_BASE_URL does not match the name on the certificate. Fix both, then docker compose up -d --force-recreate.
The console loads but every call fails. VITE_BACKEND_URL is wrong. It is compiled into the console at build time, so change it and rebuild: docker compose up -d --build frontend.
The administrator account was not created. INITIAL_ADMIN_MODE is skip, or the bootstrap ran before the identity provider was ready. Set it to create and re-run docker compose up -d admin-bootstrap — it no-ops if an administrator already exists.
Everything is healthy and a scan returns nothing. Check the deployment response's skipped count, then the collector worker's log. More in Installation Troubleshooting.