llm-systems-manager

Docker Compose — control plane

One-command bring-up of the control plane — the Flask manager, the alarm engine, and InfluxDB v2 — for users who don’t want to run the installer.

Agents are not containerized. They read host sensors, GPUs, systemd units, and PTYs, so they run natively on each monitored host — install them with the regular installer (mode 5). See the top-level README.

Quick start

No repo checkout needed — the images carry all the code. Grab the two files the stack reads and go:

base=https://raw.githubusercontent.com/llmsyscore/llm-systems-manager/main
curl -O "$base/docker-compose.yml"
curl -o .env "$base/.env.example"
# fill in LSM_INFLUX_PASSWORD, LSM_INFLUX_TOKEN, LSM_AE_INGEST_TOKEN
# (openssl rand -hex 32 makes good tokens)
docker compose up -d          # pulls the published multi-arch images

Then open http://<docker-host>:5000/ and log in (default llmadmin / llmadmin — change the password from Admin → Authentication).

Images are published to ghcr.io on every release tag (amd64 + arm64):

Pin a version with LSM_IMAGE_TAG=v1.0.0 in .env. To build from source instead of pulling, clone the repo and run docker compose up -d --build.

Configuration

Both services read config/llm-systems.toml. In containers the entrypoint renders it from LSM_* environment variables on every start (see .env.example for the full list); anything not covered falls back to the defaults in config/unified_config.py.

Need a key the env vars don’t cover? Bind-mount your own TOML and it is left untouched (bind mounts are detected via /proc/self/mounts; if you instead copy a generated file around, also delete its # GENERATED … marker line):

    volumes:
      - ./my-llm-systems.toml:/opt/llm-systems-manager/config/llm-systems.toml

Tokens rendered into the TOML must not contain " or \ (hex/base64 tokens are fine).

The dashboard is served by the manager on port 5000; the alarm engine and InfluxDB are reached through the manager, so browse to the manager, not to :8081/:8086 directly.

Native agents against a containerized manager

Agents run natively on each host and dial the manager at this docker host’s LAN address. Point each agent’s MANAGER_URL at http://<docker-host-LAN-IP>:5000, and set LSM_MANAGER_PUBLIC_HOST to that same host — this one setting makes native agents work end-to-end:

Do not set LSM_ALARM_ENGINE_URL to the host LAN IP — that is the URL the manager itself uses for its own AE calls and must stay at the compose service name (http://alarm-engine:8081, the default). Setting it to the host IP makes every manager→AE call fail (the container can’t reach the host’s own published port).

The manager’s own host metrics

The manager runs in a container, so it can’t auto-detect which registered agent runs on its host (the container hostname is a random id and the agent arrives via the compose bridge). Install an agent on the docker host, approve it, then in Admin → Agents tick manager host on that agent’s row. This scopes the manager-host CPU/RAM/Disk cards to it and shows the manager / alarm-engine / InfluxDB version pills. Without it those stay empty — the metrics gap is expected until you designate the host agent.

Restarting the control plane

The Admin tab’s Restart buttons work in containers: the manager restarts by exiting (the runtime respawns it), and the alarm engine restarts itself over its management API. Both rely on the compose restart: unless-stopped policy, so keep it in place (a bare docker run with no restart policy would just stop).

Notifications

Set LSM_SMTP_* and/or LSM_DISCORD_WEBHOOK_URL to wire up alert delivery; they are only written to the config when provided. Anything else (Twilio, per-rule channels) is configured via a bind-mounted TOML.

Hardening notes

TLS / internal CA

Works the same as a co-located bare-metal install:

Ports

Port Service What
5000 manager dashboard + API (HTTP)
5443 manager dashboard + API (HTTPS, internal CA)
5444 manager /ws/alarm WebSocket proxy
5445 manager llama-state SSE daemon
8081 alarm engine agent metric ingest + alarms API/UI
8086 influxdb not published by default (compose-internal)

Persistence

Named volumes: manager-data (SQLite benchmarks, agent registry, internal CA, backups), ae-data (alert/rule SQLite DBs + AE TLS cert), influxdb-data / influxdb-config (metric history). docker compose down -v deletes all of it.

Updating

docker compose pull && docker compose up -d

Data migrations run automatically at service startup, same as a bare-metal update.

Don’t run the bare-metal updater (tools/installer/update.sh / install.sh --update) inside the containers — it detects container context and exits with the image-pull instruction above (changes inside a container are ephemeral and there is no systemd to restart).