Skip to content

Installation and Self-Hosting

If you just want to use RELab, start here:

app.cml-relab.org

No local setup is required.

Self-hosting makes sense for evaluation, institutional deployment, offline use, or local development. If your main goal is contributing code, CONTRIBUTING.md is the better starting point.

This page is about running the stack. For manifest conventions, tooling policy, and contributor workflow, use the engineering and contributing docs instead.

  1. Clone the repository.

    Terminal window
    git clone https://github.com/CMLPlatform/relab
    cd relab
  2. Install local tooling if you plan to modify code.

    Terminal window
    just setup
  3. Configure the backend environment.

    Terminal window
    cp backend/.env.dev.example backend/.env.dev
  4. Run the first migration pass.

    Terminal window
    just dev-migrate

    If you also need CPV or HS taxonomy seeding in the migration container:

    Terminal window
    BACKEND_MIGRATIONS_INCLUDE_TAXONOMY_SEED_DEPS=true docker compose --profile migrations up --build migrator
  5. Start the stack.

    Terminal window
    just dev

    If you do not want file watching, use just dev-up instead.

  6. Open the local services.

  7. Verify the backend is healthy.

    Terminal window
    curl http://127.0.0.1:8011/health
  8. Run checks if needed.

    Terminal window
    just ci
    just test

Deploys use a single compose overlay, compose.deploy.yaml. The host’s root .env decides whether the stack comes up as prod or staging — one file, one command, no extra flags. Cloudflare Tunnel remains the supported ingress path. The current operational path is manual on the server: pull the repo, run the deploy stack, run migrations, verify health.

  1. Configure a Cloudflare tunnel.

    • Set up a domain and a remotely managed tunnel in Cloudflare.
    • Forward traffic to app-site:8081, web-site:8081, api:8000, and docs-site:8000.
  2. Copy .env.example to .env and fill in values.

    Terminal window
    cp .env.example .env
    • Prod host: set TUNNEL_TOKEN=<prod token>; leave the commented “staging overrides” block commented. Defaults resolve to ENVIRONMENT=prod, WEB_CONCURRENCY=4, project relab_prod.
    • Staging host: uncomment the staging block (APP_ENV=staging, COMPOSE_PROJECT_NAME=relab_staging, WEB_CONCURRENCY=2, BUILD_MODE=staging, PUBLIC_SITE_URL=…, CSP_API_ORIGIN=…) and set TUNNEL_TOKEN=<staging token>.
  3. Configure the backend runtime environment for this host.

    Terminal window
    cp backend/.env.prod.example backend/.env.prod # on a prod host
    # OR
    cp backend/.env.staging.example backend/.env.staging # on a staging host
  4. Start the stack.

    Terminal window
    just prod-up YES

    In the current setup, deployment is done directly on the server.

  5. Run migrations.

    Terminal window
    just prod-migrate YES

    If you also need taxonomy seeding in the migration container:

    Terminal window
    BACKEND_MIGRATIONS_INCLUDE_TAXONOMY_SEED_DEPS=true docker compose -p relab_prod -f compose.yaml -f compose.deploy.yaml --profile migrations up --build migrator
  6. Manage the running stack.

    Terminal window
    just prod-logs
    just prod-down YES

If you run a central monitoring stack (Grafana + Loki + Tempo + Prometheus), prod and staging can ship to it without any code changes:

  1. Install the Loki Docker driver plugin on the host (once):

    Terminal window
    docker plugin install grafana/loki-docker-driver:latest --alias loki --grant-all-permissions
  2. Set LOKI_URL (and optionally OTEL_EXPORTER_OTLP_ENDPOINT) in the host’s root .env. The prod-up / staging-up recipes auto-include compose.logging.loki.yaml when LOKI_URL is non-empty. Hosts without the variable keep Docker’s default json-file driver.

See the engineering ops telemetry section for the full flow.

Staging is a first-class operational environment and follows the same manual server-side flow as production.

  1. Configure the backend staging environment.

    Terminal window
    cp backend/.env.staging.example backend/.env.staging
  2. Start the staging stack.

    Terminal window
    just staging-up YES
  3. Run migrations.

    Terminal window
    just staging-migrate YES
  4. Manage the running stack.

    Terminal window
    just staging-logs
    just staging-down YES

If you want camera-assisted capture, see the external plugin repository:

Raspberry Pi Camera Plugin

The plugin uses WebSocket relay — the RPi connects outbound to the backend, so no public IP or port forwarding is needed. The quickest setup is automatic pairing: set PAIRING_BACKEND_URL on the RPi, boot it, and enter the displayed pairing code in the app. See the plugin install guide and the platform camera guide for details. If the Pi is headless, you can read the pairing code either from its local /setup page or from the PAIRING READY log line over SSH, docker compose logs, or journalctl.