Skip to content

Latest commit

 

History

History
176 lines (125 loc) · 8.53 KB

setup.md

File metadata and controls

176 lines (125 loc) · 8.53 KB

Setup

First-time setup for running Yggdrasil locally with Docker Compose.

Prerequisites

  • Docker and Docker Compose
  • A Docker network shared by everyone running this stack on the host (see below)

External dependencies

Two infrastructure pieces sit outside the Django app's own code and are easy to overlook:

  • Redis — started as the redis service in docker-compose.yml (so docker compose up brings it up for you), but it isn't just an internal cache: it's the Celery broker the runner worker consumes jobs from (see docs/runners.md). It is published on loopback only; keep it that way. If you change REDIS_PASSWORD, update CELERY_BROKER_URL in .env.worker too.
  • Garage (or any S3-compatible object store, e.g. MinIO) — not part of docker-compose.yml at all. It's a fully external service that must already be running and reachable from the yggdrasil-web-$DOCKER_SUFFIX container at OBJECT_STORAGE_ENDPOINT_URL (.env.example defaults to http://garage:3900). Make sure that container can actually resolve/reach the garage host — either join the same Docker network Garage is on, or point OBJECT_STORAGE_ENDPOINT_URL at a routable address — otherwise uploads/exports will fail with object storage errors (check /api/processing/health/, see docs/running.md).

1. Pick a DOCKER_SUFFIX

Every container, network, and project name in docker-compose.yml is suffixed with $DOCKER_SUFFIX, e.g. yggdrasil-web-$DOCKER_SUFFIX, app-net-$DOCKER_SUFFIX. This lets multiple stacks (your dev instance, a teammate's, production) run on the same host without colliding.

Pick something unique to you, e.g. dev-yourname, or prod for the production deployment.

2. Create your .env file

cp .env.example .env

Edit .env and set at minimum:

  • DOCKER_SUFFIX — the value you picked above
  • UID / GID — your host user/group id (id -u / id -g), so files written by the container are owned by you
  • SECRET_KEY — any random string for Django
  • MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD, MYSQL_ROOT_PASSWORD
  • REDIS_PASSWORD
  • RUNNER_API_TOKENS — token(s) the external runners will use

docker-compose.yml always reads from .env in the repo root (env_file: .env), so make sure that's the file you edited.

3. Create the shared Docker network

The app-net-$DOCKER_SUFFIX network is declared as external: true, meaning Compose expects it to already exist — it won't create it for you:

docker network create app-net-$DOCKER_SUFFIX

You also need the proxy-net external network (shared reverse proxy network), if it doesn't already exist on the host:

docker network create proxy-net

4. Bring the stack up

See running.md for day-to-day commands. The short version:

docker compose --env-file .env up -d --build

This builds the web image, then starts the app services (web, beat, maintenance-worker, db, and redis). The runner-worker is also defined in the compose file, but it is deliberately not attached to app-net-$DOCKER_SUFFIX; configure .env.worker, the SSH key, and the known-hosts mount before relying on it for SLURM dispatch.

5. Run migrations

entrypoint.sh runs migrate --noinput on container start by default. If your stack shares a database with another stack that owns migrations, opt out with AUTO_MIGRATE=0 in .env and run migrations manually:

export DOCKER_SUFFIX=YOUR-DOCKER-SUFFIX
docker exec -it yggdrasil-web-$DOCKER_SUFFIX python manage.py migrate

The container serves the Django ASGI application with Uvicorn (ASGI_WORKERS and ASGI_KEEP_ALIVE are tunable via .env). For local development with auto-reload, set RUN_DEV_SERVER=1; the entrypoint will run Uvicorn with --reload so the live transcription WebSocket remains available.

6. Seed projects, modalities, and create admin account

Each project app ships a management command that creates its Project row and registers its Modality rows (file types it accepts). The database is empty without this — uploads will fail until it's run, since Patient.modalities and upload forms validate against existing Modality records.

Quick setup for local development (recommended)

For local development, run seed_dev. This single command seeds all projects and modalities, creates a superuser account (admin / admin), configures the required ProjectAccess roles, and creates initial demo patients:

docker exec -it yggdrasil-web-$DOCKER_SUFFIX python manage.py seed_dev

You can then log in at http://localhost:8000 with:

  • Username: admin
  • Password: admin

Individual / production commands

For production deployments or fine-grained seeding, run the individual commands:

# Maxillo: CBCT, IOS, intraoral photos, teleradiography, panoramic, raw zip
docker exec -it yggdrasil-web-$DOCKER_SUFFIX python manage.py create_maxillo_modalities

# Brain: reuses the same Patient/Modality model under its own project namespace
docker exec -it yggdrasil-web-$DOCKER_SUFFIX python manage.py setup_brain_modalities

# Laparoscopy: video modality
docker exec -it yggdrasil-web-$DOCKER_SUFFIX python manage.py setup_laparoscopy_modalities

# Urology: MRI, WSI digital pathology, confocal
docker exec -it yggdrasil-web-$DOCKER_SUFFIX python manage.py setup_urology_modalities

These are idempotent (get_or_create + update) — safe to re-run after upgrades that add/change modalities.

To create an admin superuser manually (e.g., in production where seed_dev refuses to run when DEBUG=False):

docker exec -it yggdrasil-web-$DOCKER_SUFFIX python manage.py createsuperuser

7. Configure Live Whisper

Microphone captions stream through an authenticated Yggdrasil WebSocket relay. Configure the upstream shared token in .env; it is never exposed to browsers:

WHISPER_WS_URL=wss://155.185.48.254:9097/ws
WHISPER_API_TOKEN=replace-with-the-server-token
WHISPER_CA_CERT=/app/certs/whisper-live.pem

The tracked certificate pins the current self-signed Live Whisper certificate. Verify its SHA-256 fingerprint before deployment: C8:34:A6:FC:93:65:E8:76:B6:11:83:0F:38:C6:12:D7:3E:E9:45:D4:07:F3:48:CB:EC:30:E0:21:50:F3:70:F8. It expires on 23 July 2027 and must be replaced when the upstream certificate is rotated. Connect by 155.185.48.254, not pdor.ing.unimore.it, because the current certificate contains the IP address but not that DNS name.

The public reverse proxy must pass WebSocket upgrade requests for /ws/live-transcription/ to the web container. The standard nginx-proxy setup used by docker-compose.yml handles WebSocket upgrades automatically.

8. Configure assisted segmentation (optional)

The Assist tool in laparoscopy Annotation Mode turns clicked points into masks using a model on the DjangoWorker GPU worker. The browser never reaches the worker. Its WebSocket (/ws/assist/…) ends at Yggdrasil, which opens the worker session itself. Leave both values empty to hide the tool.

# Base URL, no path. Yggdrasil calls <url>/api/session/... and opens <url>/ws/session/...
ASSIST_WORKER_URL=https://gpu-worker.example.org
# The worker's WORKER_API_TOKEN
ASSIST_WORKER_TOKEN=replace-with-the-worker-token
# ASSIST_CONNECT_TIMEOUT=10
  • Where the worker is. Behind a reverse proxy (which must route /api/session and /ws/session to it), use its public https:// URL; the socket then uses wss://. If it shares a Docker network with web, use its service address there, e.g. http://assist-worker:8000. Only http(s) URLs are accepted, and certificates are checked against the system CAs.
  • The worker gets a link, not storage credentials. For each session Yggdrasil signs a 10-minute download link to that one video, against its own OBJECT_STORAGE_ENDPOINT_URL. So that endpoint must be reachable from the worker, and the worker's VIDEO_SOURCE_ORIGINS must list its origin (scheme://host[:port], e.g. https://s3.example.org). The worker refuses links to any other origin and does not follow redirects. One worker can serve several deployments by listing each one's storage origin.
  • The project. The tool also needs the assisted_segmentation annotation method on the project. Migration 0063 enables it on every laparoscopy project, and setup_laparoscopy_modalities does the same for a new one.
  • After changing .env, recreate web (docker compose up -d web); a restart does not re-read env_file. The page shows the tool as Unavailable if the worker cannot be reached.