Self-hosted installation
This guide deploys the complete Logos stack with Docker Compose. The stack
contains the web UI, API service, orchestrator, PostgreSQL, and Traefik.
The development stack additionally runs a local Keycloak; production expects
an external identity provider configured via the KEYCLOAK_* variables in
.env.
Prerequisites
- Docker Engine with the Compose plugin
- A domain name and an SMTP/identity-provider setup for production
- Python 3.13 and
uvonly when developing Logos outside containers - A GPU worker node when serving local models
Clone the repository and enter the service directory:
git clone https://github.com/ls1intum/edutelligence.git
cd edutelligence/logos
cp .env.example .env
Development deployment
The development compose file builds all services locally and includes a development Keycloak realm:
docker compose -f docker-compose.dev.yaml up --build
The compose stack serves the API (Traefik at http://localhost:18081) but
not the web UI. Start the Angular dev server on the host as well:
cd logos-ui
npm ci
npm start
Then open http://localhost:4200/ and sign in with one of the seeded
development accounts. These accounts and their roles are defined in
keycloak/tum-realm.json; never use them in a production deployment.
Production deployment
For production, use docker-compose.yaml. Every image is published to the
public mirror at ghcr.io/ls1intum/edutelligence, which is what the compose
file pulls by default — no registry configuration and no login:
docker compose --env-file .env up -d
The mirror is fed by main, so it carries one tag: latest. Version tags go
to the project's deployment registry, which is team-internal. To pull from
that registry, or from a mirror of your own, set both in .env and log in
once:
REGISTRY=<registry-host>/<namespace>
IMAGE_TAG=<published tag>
docker login <registry-host> # host only, no path
To run images you built yourself, build them from the Dockerfiles the build workflow uses and tag them for a registry the host can pull from (e.g. a local registry):
# The build contexts below are repository-root relative — return there
# first (the guide's working directory is edutelligence/logos):
cd ..
REGISTRY=localhost:5000
IMAGE_TAG=latest
docker build -t "$REGISTRY/logos:$IMAGE_TAG" -f logos/logos-orchestrator/Dockerfile .
docker build -t "$REGISTRY/logos-webservice:$IMAGE_TAG" logos/logos-webservice
docker build -t "$REGISTRY/logos-ui:$IMAGE_TAG" logos/logos-ui
docker build -t "$REGISTRY/logos-db:$IMAGE_TAG" logos/db
docker build -t "$REGISTRY/logos-agent:$IMAGE_TAG" -f logos/logos-agent/Dockerfile .
docker build -t "$REGISTRY/logos-agent-gateway:$IMAGE_TAG" -f logos/agent-gateway/Dockerfile .
docker build -t "$REGISTRY/logos-agent-workspace:$IMAGE_TAG" -f logos/logos-agent/workspace/Dockerfile .
docker build -t "$REGISTRY/logos-rate-gateway:$IMAGE_TAG" -f logos/rate-limit-gateway/Dockerfile .
(All eight images are required to run the full stack: logos-rate-gateway is
the only router on the public entrypoints, so without it the stack serves no
public traffic at all, and the agent runner refuses to start a session when
the logos-agent-workspace image is absent.)
Set the same REGISTRY and IMAGE_TAG in .env, then start the stack
(the worker node image is built on the GPU host instead — see the worker
node guide):
cd logos
docker compose --env-file .env up -d
Set a real LOGOS_DOMAIN, ACME_EMAIL, LOGOS_CORS_ALLOWED_ORIGINS, and
strong values for LOGOS_INTERNAL_SECRET and PROMETHEUS_API_KEY. Ensure
the host's ports 80, 443, and (if required) 8080 are available. Traefik
obtains a certificate through Let's Encrypt when ACME_EMAIL is configured.
After startup, verify the UI at https://<your-domain>/ and the API
documentation at https://<your-domain>/docs.
Persistent data and upgrades
The production stack persists the following:
| Storage | Type | Contents |
|---|---|---|
postgres_data | named volume | PostgreSQL data |
data_volume | named volume | orchestrator working data (/src/logos) |
agent_artifacts | named volume | agent session artifacts |
agent_state (literal name logos_agent_state) | named volume | agent session state |
./letsencrypt | bind mount | Traefik Let's Encrypt certificate state |
Back up these volumes and the ./letsencrypt directory before upgrades.
Keycloak is external to the stack, so back up its realm export (see
keycloak/tum-realm.json in this repository for the realm format) together
with your identity provider; in the development stack Keycloak state is
ephemeral. Pull the desired image tag and recreate the stack:
docker compose --env-file .env pull
docker compose --env-file .env up -d