Deploy with Docker Compose
Set Komodo CD up by hand, put it behind HTTPS, pin a version or build the images from source.
The one-line installer does all of this for you. This page is the same installation step by step, plus what to change for HTTPS and fixed versions.
1. Get the compose file
mkdir komodo-cd && cd komodo-cd
curl -fsSLO https://raw.githubusercontent.com/Nonetss/Komodo-CD/main/compose.yml
curl -fsSL https://raw.githubusercontent.com/Nonetss/Komodo-CD/main/.env.example -o .env
2. Generate the secrets
# Better Auth secret (required)
openssl rand -base64 32
# Initial admin password (required)
openssl rand -base64 16
3. Fill in .env
At least these three variables:
APP_URL=https://deploy.example.com
BETTER_AUTH_SECRET=<output of the first command>
SEED_ADMIN_PASSWORD=<output of the second command>
APP_URL is the URL the browser and your CI will use, without a trailing slash. Every variable is described in Configuration.
4. Start
docker compose up -d
The app answers on the port set in PORT (default 80). On its first start the backend creates the SQLite database in the db_data volume, applies the migrations and creates the admin.
The compose file
services:
backend:
image: ghcr.io/nonetss/komodo-cd-backend:latest
init: true
restart: unless-stopped
volumes:
- db_data:/data
environment:
DATABASE_URL: "file:/data/db.sqlite"
BETTER_AUTH_URL: "${APP_URL:?APP_URL is required}"
BETTER_AUTH_SECRET: "${BETTER_AUTH_SECRET:?BETTER_AUTH_SECRET is required}"
SEED_ADMIN_EMAIL: "${SEED_ADMIN_EMAIL:-admin@example.com}"
SEED_ADMIN_NAME: "${SEED_ADMIN_NAME:-Admin}"
SEED_ADMIN_PASSWORD: "${SEED_ADMIN_PASSWORD:?SEED_ADMIN_PASSWORD is required}"
TRIVY_SERVER_URL: "${TRIVY_SERVER_URL:-http://trivy:4954}"
TRIVY_RESCAN_INTERVAL_HOURS: "${TRIVY_RESCAN_INTERVAL_HOURS:-24}"
healthcheck:
test: ["CMD", "bun", "-e", "fetch('http://localhost:3000/health-check').then((r) => process.exit(r.ok ? 0 : 1), () => process.exit(1))"]
interval: 10s
timeout: 5s
retries: 5
start_period: 15s
networks:
- komodo_net
frontend:
image: ghcr.io/nonetss/komodo-cd-frontend:latest
init: true
restart: unless-stopped
environment:
BACKEND_URL: "http://backend:3000"
healthcheck:
test: ["CMD", "bun", "-e", "fetch('http://localhost:4321/login').then((r) => process.exit(r.ok ? 0 : 1), () => process.exit(1))"]
interval: 10s
timeout: 5s
retries: 5
start_period: 15s
depends_on:
backend:
condition: service_healthy
networks:
- komodo_net
gateway:
image: ghcr.io/nonetss/komodo-cd-gateway:latest
init: true
restart: unless-stopped
ports:
- "${PORT:-80}:80"
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost/health"]
interval: 10s
timeout: 5s
retries: 5
start_period: 5s
depends_on:
backend:
condition: service_healthy
frontend:
condition: service_healthy
networks:
- komodo_net
# Trivy server for the Security page: keeps the vulnerability database and
# receives the scans the backend sends with its `trivy` client (same
# version as TRIVY_VERSION in apps/backend/Dockerfile).
trivy:
image: aquasec/trivy:0.75.0
init: true
restart: unless-stopped
command: ["server", "--listen", "0.0.0.0:4954", "--cache-dir", "/var/lib/trivy"]
volumes:
- trivy_cache:/var/lib/trivy
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:4954/healthz"]
interval: 10s
timeout: 5s
retries: 5
# The first start downloads the database before listening
start_period: 120s
networks:
- komodo_net
networks:
komodo_net:
volumes:
db_data:
trivy_cache:
Only the gateway publishes a port. It sends the API to backend:3000 and every page to frontend:4321 over the Compose network, so neither app needs to be exposed. The trivy service is only reached by the backend, to scan images for the Security page (see Configuration).
Behind HTTPS
The gateway serves plain HTTP on port 80 and does not request certificates. Terminate TLS in front of it with the reverse proxy you already use, and set APP_URL to the https:// URL: Better Auth uses it as the trusted origin, so signing in fails if it does not match the address in the browser.
For example, publish Komodo CD on a local port and let a Caddy on the host handle the certificate:
PORT=8080
APP_URL=https://deploy.example.com
deploy.example.com {
reverse_proxy localhost:8080
}
Pin a version
The images are published as latest (the main branch) and with the version of every release (1.0.0, 1.0). To stay on one, change the tags in compose.yml:
image: ghcr.io/nonetss/komodo-cd-backend:1.0.0
# …
image: ghcr.io/nonetss/komodo-cd-frontend:1.0.0
Keep both images on the same version.
Build the images from source
From a clone of the repository, compose.build.yml extends the same services but builds the images from the monorepo:
git clone https://github.com/Nonetss/Komodo-CD.git
cd Komodo-CD
cp .env.example .env # and fill it in
docker compose -f compose.build.yml up -d --build
bun run docker:up is a shortcut for the same command.