Deployment
Assessors Studio is distributed as a single container image that serves both the Vue 3 single-page application and the JSON API on the same origin. This page covers the three supported deployment topologies: a quick-start evaluation install, a production install against PostgreSQL, and a reverse-proxy fronted deployment with TLS.
The canonical image is docker.io/cyclonedx/cyclonedx-assessors-studio. Snapshot tags are published from the main branch; versioned tags are published from GitHub releases; latest tracks the most recent non-prerelease.
Quick start with PGlite
Section titled “Quick start with PGlite”PGlite is an embedded PostgreSQL implementation that lives inside the container. It is ideal for evaluation, single-operator use, and small installations that do not need an external database.
Download the evaluation Compose file:
curl -O https://raw.githubusercontent.com/CycloneDX/cyclonedx-assessors-studio/main/deploy/docker/docker-compose.ymlStart the stack:
docker compose up -dThe application is available at http://localhost:3001. The first request is redirected to the setup wizard, where you create the initial administrator account. See First Login for the wizard walkthrough.
The Compose file defines a single app service and an app-data named volume that holds the embedded database. No environment variables are required; the backend generates a JWT signing secret on first run and persists it alongside the rest of the application state.
To override settings, create a .env file next to the Compose file or pass variables on the command line:
APP_PORT=8080 JWT_SECRET=... docker compose up -dThe full list of variables is in the Environment Variables reference. The most common override in an evaluation install is APP_PORT to publish on something other than 3001.
Production with PostgreSQL
Section titled “Production with PostgreSQL”Production installations should use an external PostgreSQL 17 database. The production Compose file runs a db service and an app service, with the app depending on the database’s health check.
Download the production Compose file:
curl -O https://raw.githubusercontent.com/CycloneDX/cyclonedx-assessors-studio/main/deploy/docker/docker-compose.production.ymlSet at minimum POSTGRES_PASSWORD and APP_IMAGE (pinned to a specific snapshot tag for production; no stable release is available yet):
export APP_IMAGE=cyclonedx/cyclonedx-assessors-studio:snapshot-20260412-abc1234export POSTGRES_PASSWORD=<generated-strong-password>docker compose -f docker-compose.production.yml up -dFor multi-replica production, set JWT_SECRET explicitly so every replica signs with the same secret. A generated 32+ character random string is suitable:
JWT_SECRET=$(openssl rand -hex 32)If you manage the database outside of Docker (managed PostgreSQL service), remove the db service from the Compose file and point DATABASE_URL at your instance. Every setting driven by DATABASE_URL is documented on the Environment Variables page.
Behind a reverse proxy
Section titled “Behind a reverse proxy”Assessors Studio does not terminate TLS. For production you should place a reverse proxy in front of the container. Any proxy works: nginx, Caddy, Traefik, HAProxy, a cloud load balancer. The proxy responsibilities are:
- Terminate TLS on port 443 with a valid certificate.
- Forward decrypted traffic to the application on port 3001.
- Set standard proxy headers (
X-Forwarded-For,X-Forwarded-Proto,X-Forwarded-Host).
Example with Caddy:
studio.example.com { reverse_proxy app:3001}Example with nginx:
server { listen 443 ssl http2; server_name studio.example.com; ssl_certificate /etc/ssl/fullchain.pem; ssl_certificate_key /etc/ssl/privkey.pem;
location / { proxy_pass http://app:3001; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; }}Set APP_URL and CORS_ORIGIN on the application to the public URL so notification links and API call origins are correct:
APP_URL=https://studio.example.comCORS_ORIGIN=https://studio.example.comRunning without Docker Compose
Section titled “Running without Docker Compose”The image can be run directly with docker run or deployed via any container orchestrator (Kubernetes, Nomad, ECS). The runtime requirements are:
- Port 3001 reachable inside the cluster.
- A writable data volume mounted at
/app/dataif PGlite is in use, or network access to PostgreSQL if the external provider is configured. - Access to the configured evidence storage (the database itself or an S3-compatible endpoint).
- Outbound access to any configured notification endpoints.
The Environment Variables reference lists every setting that controls runtime behavior.
Verifying the install
Section titled “Verifying the install”Check the health endpoint:
curl http://localhost:3001/api/healthA healthy instance returns {"status":"ok"}. The /metrics endpoint (when METRICS_ENABLED=true) exposes Prometheus metrics. Application logs stream to stdout in JSON format; capture them with your usual container log pipeline.
What to do next
Section titled “What to do next”After the container is healthy:
- Complete the setup wizard (First Login).
- Invite co-administrators (Users and Permissions).
- Configure the notification channels your organization uses (Integrations).
- Decide on storage for evidence (Evidence Storage).
- Enable encryption at rest if applicable (Encryption at Rest).
- Plan your first backup schedule (Backup and Recovery).