Skip to content

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.

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:

Terminal window
curl -O https://raw.githubusercontent.com/CycloneDX/cyclonedx-assessors-studio/main/deploy/docker/docker-compose.yml

Start the stack:

Terminal window
docker compose up -d

The 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:

Terminal window
APP_PORT=8080 JWT_SECRET=... docker compose up -d

The 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 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:

Terminal window
curl -O https://raw.githubusercontent.com/CycloneDX/cyclonedx-assessors-studio/main/deploy/docker/docker-compose.production.yml

Set at minimum POSTGRES_PASSWORD and APP_IMAGE (pinned to a specific snapshot tag for production; no stable release is available yet):

Terminal window
export APP_IMAGE=cyclonedx/cyclonedx-assessors-studio:snapshot-20260412-abc1234
export POSTGRES_PASSWORD=<generated-strong-password>
docker compose -f docker-compose.production.yml up -d

For multi-replica production, set JWT_SECRET explicitly so every replica signs with the same secret. A generated 32+ character random string is suitable:

Terminal window
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.

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.com
CORS_ORIGIN=https://studio.example.com

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/data if 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.

Check the health endpoint:

Terminal window
curl http://localhost:3001/api/health

A 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.

After the container is healthy:

  1. Complete the setup wizard (First Login).
  2. Invite co-administrators (Users and Permissions).
  3. Configure the notification channels your organization uses (Integrations).
  4. Decide on storage for evidence (Evidence Storage).
  5. Enable encryption at rest if applicable (Encryption at Rest).
  6. Plan your first backup schedule (Backup and Recovery).