Run CompanyWizard Web with Docker Compose (Site)
AdminCompanyWizard’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.
Overview
Section titled “Overview”- 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.
Prerequisites
Section titled “Prerequisites”- 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).
Compose example
Section titled “Compose example”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:Environment variables
Section titled “Environment variables”Every setting is an environment variable using ASP.NET Core’s __ (double-underscore) section separator.
| Variable | Required | Notes |
|---|---|---|
Encryption__ApiKeySecret | yes | ≥ 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__SecretKey | yes | ≥ 32 chars. Signs auth tokens. |
Cors__AllowedOrigins__0 | yes | Public origin(s) allowed to call the API + SignalR hub. Startup hard-fails if empty. Add __1, __2, … for more. |
Knowledge__FolderPath | yes (Docker) | Knowledge-base root. Put it on a volume. |
Import__StagingRoot | yes (Docker) | Import staging dir. Keep on the same volume as Knowledge__FolderPath so KB promotion is an atomic move. |
Qdrant__QdrantEndpoint | for RAG | Qdrant gRPC endpoint, e.g. http://qdrant:6334. Omit to run without vector search. |
ConnectionStrings__CompanyWizardDb | no | Defaults to Data Source=companywizard.db. Point at your data volume to persist. |
Licensing__Token | no | Signed license token. Unset ⇒ Free floor. Prefer the admin license page (persists across restarts). |
The container port is always 8080 (ASPNETCORE_URLS=http://+:8080).
Start & health
Section titled “Start & health”docker compose up -dcurl -f http://localhost:8080/alive # -> 200 once the container is liveThen open http://localhost:8080 (or your proxied HTTPS URL). First launch walks you through admin setup.
Activate the license
Section titled “Activate the license”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 providers
Section titled “Configure providers”Configure LLM, embedding and OCR providers after first login in the admin UI — they are stored encrypted in the DB, not in env vars.
Operations & pitfalls
Section titled “Operations & pitfalls”- 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
toomanyrequestson busy hosts. - Reverse proxy / TLS: the container speaks plain HTTP on
8080. Terminate TLS at a proxy and setCors__AllowedOrigins__0to the public HTTPS URL. - Rotating
Encryption__ApiKeySecretinvalidates stored API keys — re-enter them in the admin UI afterwards. - Backups: back up only the
cw-datavolume (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.