Deployment
CM Box runs as a small set of cooperating containers: four application services built from the container images provided with your license, plus two Redis instances and a text-extraction service. This page describes what each service does, how they connect, and the three supported ways to deploy them.
Requirements
Section titled “Requirements”- Docker — all deployment options run CM Box as containers. On Windows or macOS use Docker Desktop; on Linux the Docker engine is sufficient.
- Node.js 22.x+ — only needed if you run the application from source
rather than from the provided images. The
appandgraphqlimages are built on Node 22; theprocessimage on Node 24. - Container images — the four CM Box images (
app,graphql,process,web) provided with your license, pulled into your own container registry or environment. - A product license — required from version 1.5.0 onward; see Instance setup and licensing.
Service topology
Section titled “Service topology”| Service | Image | Port | Role |
|---|---|---|---|
app |
CM Box app image |
4321 | The application server: web UI, REST API, authentication middleware, and the /api/graphql/ proxy. |
graphql |
CM Box graphql image |
4000 (internal) | Apollo GraphQL server with one endpoint per repository (/graphql/:repo). Only the app service needs to reach it. |
process |
CM Box process image |
— | BullMQ queue workers: media renditions, webhook delivery, and scheduled tasks. The image bundles conversion tooling (Ghostscript, GraphicsMagick, ImageMagick, FFmpeg, LibreOffice). |
web |
CM Box web image |
80 | An nginx reverse proxy in front of app: gzip compression and a 1000 MB upload limit (client_max_body_size). |
db |
redis:latest |
6379 | The primary database. CM Box requires Redis 8.0+ with the Search and JSON modules. Runs with --appendonly yes --save 60 1 — append-only-file persistence plus a snapshot every 60 seconds. |
queue |
redis:latest |
6410 | A second Redis instance dedicated to the BullMQ job queues, run with --maxmemory-policy noeviction so queued jobs are never evicted. |
extraction |
apache/tika:latest-full |
9998 (internal) | Apache Tika text extraction, used during content processing (default endpoint http://extraction:9998/tika/text, overridable with EXTRACTION_URL). Included in the Kubernetes manifest and the development stack; the single-host Compose file does not define it, so add it there (or point EXTRACTION_URL at an external Tika) if you need document text extraction. |
Request flow: clients reach web (port 80), which proxies to app
(port 4321). The app proxies GraphQL calls to graphql (port 4000) via
GRAPHQL_SERVER_ENDPOINT. All application services connect to db via
REDIS_URL; the app and process services also connect to queue via
BULLMQ_REDIS_HOST/BULLMQ_REDIS_PORT. Every service is configured through
environment variables — see the
environment variable reference.
Both Redis instances hold state and must have persistent volumes: db is the
system of record for all content, configuration, and security objects, and
queue holds in-flight background jobs.
Deployment options
Section titled “Deployment options”Docker Compose
Section titled “Docker Compose”Two Compose files ship with the product:
local-full-deploy-compose.yml— the full stack:db,queue,app,graphql,process, andweb, with named volumes (redis_data,queue_data) for the two Redis instances. Use this as the starting point for a single-host deployment. The file ships with development values forJWT_SECRET_KEY,WORKOS_ORGANIZATION_ID, andWORKOS_DIRECTORY_ID— replace all three with your own before starting the stack.docker-compose.yml— a development dependency stack only (redis,queue,extraction,process) for running the app and GraphQL servers from source withnpm run devandnpm run graphql.
Kubernetes
Section titled “Kubernetes”cmbox-kubernetes.yaml is a reference manifest for a cluster deployment:
- StatefulSets
cmbox-dbandcmbox-queuerun the two Redis instances, each with a 40 GivolumeClaimTemplateand the same persistence flags as the Compose files. - Deployment
cmbox-appruns theappcontainer with thewebnginx container as a sidecar in the same pod, so nginx proxies tolocalhost:4321. - Deployments
cmbox-graphqlandcmbox-processrun the GraphQL server and queue workers; the Tikaextractioncontainer runs as a sidecar in the process pod. - Services:
cmbox-app-svcis a LoadBalancer on port 80 targeting the nginx sidecar (the manifest includes OCI flexible load-balancer annotations);cmbox-graphql-svc(4000),cmbox-db-svc(6379), andcmbox-queue-svc(6410) are internal. - An
imagePullSecretsentry authenticates to the registry that hosts your licensed images.
Adjust image references, hostnames (AUTH_REDIRECT_URI, GRAPHQL_ENDPOINT),
JWT_SECRET_KEY, and WorkOS IDs in the manifest’s env blocks for your
environment.
OCI Marketplace
Section titled “OCI Marketplace”The OCI Marketplace image ships with the stack preinstalled at
/opt/apps/cmbox/docker-compose.yml (the contents of
oci-marketplace-compose.yml — the full stack with restart: always). On a
new instance, run the provided cmbox-oci-new-instance.sh script, which:
- Generates a fresh 256-bit base64 key with
openssl rand -base64 32. - Replaces the
****DYNAMIC_KEY****placeholder forJWT_SECRET_KEYin the Compose file (keeping a.bakbackup). - Restarts the stack with
docker-compose down && docker-compose up -d.
This ensures every instance gets a unique JWT signing key before first use.
Verifying a deployment
Section titled “Verifying a deployment”- The app service answers
GET /healthcheckwithOk(HTTP 200) once it can reach both Redis instances; it returns HTTP 503 otherwise. - The GraphQL service exposes its own
/healthcheckon port 4000 that verifies its primary Redis connection. - Browsing to the instance for the first time redirects to the instance setup screen — continue with Instance setup and licensing.
Related
Section titled “Related”- Instance setup and licensing — first-run configuration
- Environment variable reference
- Storage backends — object storage is external to this topology
- Queues — monitoring the process service’s workers
- Upgrades — moving a deployment between releases