Skip to content

Run CompanyWizard Web with Docker Compose (Site)

Admin

CompanyWizard’s web mode runs as one container (ASP.NET API + Blazor WebAssembly UI) alongside a Qdrant vector database — sized for up to 100 users per deployment. This guide shows Site customers how to self-host the stack with docker compose and activate the Site license. Server-side API/web operation is a Site feature → License & edition model.

  • One container: API + web UI in the image evantomedia/companywizard; users work in the browser.
  • Qdrant as its own container for vector search (RAG).
  • Port 8080 (HTTP). TLS is terminated by an upstream reverse proxy (Caddy, nginx, Traefik).
  • Data: SQLite DB + knowledge base + import staging on a persistent volume.
  • Docker and Docker Compose.
  • A directory/volume for data (survives container restarts and upgrades).
  • A public URL/DNS for the reverse proxy.
  • Optionally a Site license token (without a license the app runs at the Free floor, fully evaluable).

This runs CompanyWizard plus a Qdrant vector database. Without a license the app runs at the Free floor — fully usable for evaluation; enter the license later on the admin license page.

services:
companywizard:
image: evantomedia/companywizard:latest
depends_on:
- qdrant
ports:
- "8080:8080" # front this with an HTTPS reverse proxy in production
environment:
# --- REQUIRED: app refuses to start without these ---
Encryption__ApiKeySecret: "change-me-to-a-random-32+-char-secret" # ≥ 32 chars; seeds AES-256-GCM for stored API keys
Jwt__SecretKey: "change-me-to-another-random-32+-char-secret" # ≥ 32 chars; signs auth tokens
Cors__AllowedOrigins__0: "https://companywizard.example.com" # the public URL users hit (add __1, __2 for more)
# --- REQUIRED in Docker (no sensible default exists) ---
Knowledge__FolderPath: "/data/knowledge"
Import__StagingRoot: "/data/imports" # same volume as knowledge → atomic KB promotion
ConnectionStrings__CompanyWizardDb: "Data Source=/data/companywizard.db"
# --- Vector database (RAG). Point at the Qdrant gRPC port (6334) ---
Qdrant__QdrantEndpoint: "http://qdrant:6334"
# --- OPTIONAL: license token. Leave unset to run at the Free floor. ---
# Prefer entering the token on the in-app admin license page (survives restarts);
# set it here only if you provision licenses through ops/config.
# Licensing__Token: "<signed-license-token>"
volumes:
- cw-data:/data # SQLite DB + knowledge base + import staging (single volume = atomic promotion)
restart: unless-stopped
qdrant:
image: qdrant/qdrant:latest # pin to a specific version for production
volumes:
- qdrant-data:/qdrant/storage
restart: unless-stopped
volumes:
cw-data:
qdrant-data:

Every setting is an environment variable using ASP.NET Core’s __ (double-underscore) section separator.

VariableRequiredNotes
Encryption__ApiKeySecretyes≥ 32 chars. Seeds AES-256-GCM for API keys/secrets stored in the DB. Rotating it invalidates stored keys — re-enter them in the admin UI.
Jwt__SecretKeyyes≥ 32 chars. Signs auth tokens.
Cors__AllowedOrigins__0yesPublic origin(s) allowed to call the API + SignalR hub. Startup hard-fails if empty. Add __1, __2, … for more.
Knowledge__FolderPathyes (Docker)Knowledge-base root. Put it on a volume.
Import__StagingRootyes (Docker)Import staging dir. Keep on the same volume as Knowledge__FolderPath so KB promotion is an atomic move.
Qdrant__QdrantEndpointfor RAGQdrant gRPC endpoint, e.g. http://qdrant:6334. Omit to run without vector search.
ConnectionStrings__CompanyWizardDbnoDefaults to Data Source=companywizard.db. Point at your data volume to persist.
Licensing__TokennoSigned license token. Unset ⇒ Free floor. Prefer the admin license page (persists across restarts).

The container port is always 8080 (ASPNETCORE_URLS=http://+:8080).

Terminal window
docker compose up -d
curl -f http://localhost:8080/alive # -> 200 once the container is live

Then open http://localhost:8080 (or your proxied HTTPS URL). First launch walks you through admin setup.

Without a license the app runs at the Free floor (fully evaluable). For Site operation, enter the Site license token on the admin license page — this survives restarts and is preferred over Licensing__Token in the compose file (use the latter only if you provision licenses through ops/config). What the editions differ in: License & edition model.

Configure LLM, embedding and OCR providers after first login in the admin UI — they are stored encrypted in the DB, not in env vars.

  • Docker Hub rate limit: anonymous pulls are capped (100 pulls / 6 h per IP). Log in with a free Docker account or mirror the image into your own registry, otherwise toomanyrequests on busy hosts.
  • Reverse proxy / TLS: the container speaks plain HTTP on 8080. Terminate TLS at a proxy and set Cors__AllowedOrigins__0 to the public HTTPS URL.
  • Rotating Encryption__ApiKeySecret invalidates stored API keys — re-enter them in the admin UI afterwards.
  • Backups: back up only the cw-data volume (SQLite DB + knowledge + imports). The Qdrant volume is a rebuildable projection of the knowledge base.
  • Upgrade: pull a new image tag and docker compose up -d — the data volume is preserved.