Skip to content

Docker

The production stack is defined in docker-compose.yaml. The Caddy container is the entry point to the core platform: it publishes APP_PORT on the host and forwards API requests (/api/*) to the api container, file requests (/storage/*) to the rustfs container while file storage is enabled, and every other request to the web container, which serves the single-page app. The gateway publishes its own port, GATEWAY_PORT.

Services

ServicePurposeRequired
caddyEntry point that routes requests to the other servicesYes
apiREST APIYes
webThe web app clinicians and administrators useYes
mongoDatabaseYes
gatewayServes remote assignments to participantsOnly to send remote assignments
rustfsS3-compatible object storageOnly for file instruments
playgroundInstrument playgroundNo, and it is not started by default

Keep caddy even if you already run a reverse proxy. The web app calls the API at the relative path /api, and neither the api nor the web container publishes a port, so point your own proxy at APP_PORT instead, as in the deployment tutorial.

Profiles

Every service belongs to one or more Compose profiles. Without a profile, docker compose up -d starts every service except the playground.

ProfileServices started
(none)caddy, api, web, mongo, rustfs, gateway
nogatewaycaddy, api, web, mongo, rustfs
gatewaycaddy, gateway
fullstackall seven services
playgroundplayground

To use a profile without passing --profile to every command, set COMPOSE_PROFILES in .env. Docker Compose reads it from there.

Minimal stacks

Leave docker-compose.yaml unchanged, so that updating Open Data Capture with git pull never conflicts with your changes. Choose services with a profile, and put any other change in a docker-compose.override.yaml next to it, which Docker Compose merges into docker-compose.yaml automatically.

Without the gateway

Without the gateway, the instance cannot send remote assignments. Set the following in .env:

Terminal window
COMPOSE_PROFILES=nogateway
GATEWAY_ENABLED=false

GATEWAY_ENABLED=false turns remote assignments off in the API and hides them in the web app. Leave GATEWAY_API_KEY and GATEWAY_SITE_ADDRESS as generated, because the API still checks them when it starts.

Without file storage

Without object storage, file instruments are unavailable. Set the following in .env:

Terminal window
STORAGE_ENABLED=false

The other STORAGE_* variables are then ignored. Docker Compose would still start rustfs, though: it belongs to every profile that starts the api, and the api lists it as a dependency. Create docker-compose.override.yaml next to docker-compose.yaml:

services:
api:
depends_on: !override
- mongo
rustfs:
profiles: !override
- storage

This removes rustfs from the api’s dependencies and moves it into a storage profile that nothing activates. The !override tag requires Docker Compose 2.24.4 or later.

The smallest stack

Combine the two: the .env settings from both sections above, plus the override file. The stack then runs only caddy, api, web and mongo.

To check which services will start before launching, run:

Terminal window
docker compose config --services

If a service you have just left out is still running from before, stop and remove its container, for example:

Terminal window
docker compose rm --stop gateway