# Docker Compose [`examples/compose`](../examples/compose) runs `llmman serve` behind a Caddy gateway. The same gateway exposes the built-in web UI and the Ollama, OpenAI, and Anthropic-compatible APIs. A named volume keeps pulled models between container replacements. From the repository root: ```sh docker compose -f examples/compose/compose.yaml up ``` Open for the web UI. Its Shell tab is unavailable here: the daemon binds `0.0.0.0` inside the container, and the shell is only offered by a daemon bound to loopback (see [webui.md](webui.md)). Clients can use the same address as their API base URL. For example: ```sh curl http://localhost:8080/api/version ``` The daemon binds `0.0.0.0` inside the container, which it only does with API keys or `LLMMAN_AUTH=off` ([configuration.md](configuration.md#authentication)). The example sets `LLMMAN_AUTH=off`, leaving authentication to the gateway, since the daemon's port is not published — only Caddy's is. To have the daemon check keys itself, clear that and set the keys — `LLMMAN_AUTH= LLMMAN_API_KEYS= docker compose ... up`; the web UI then asks for one. The service runs the published `ai/llmman:server` image ([backends.md](backends.md#in-a-container)). Pin a release, or pick a GPU variant, with `LLMMAN_TAG`: ```sh LLMMAN_TAG=server-0.1.400 docker compose -f examples/compose/compose.yaml up ``` The `llmman-data` volume is mounted at `/root/.local/share/llmman`, the store and cache's default location. Remove the deployment while retaining its models with `docker compose -f examples/compose/compose.yaml down`. Add `--volumes` only when the stored models should be deleted as well. ## CPU limits and container backends `LLMMAN_CPUS` controls the Compose CPU limit and defaults to `4`. The example uses llmman's default local backend, so the `llama-server` child shares the service's cgroup and llmman can derive its thread count from that limit. With `--runtime docker` or `--runtime podman` the backend runs in a separate container, a sibling of the service. The service's limit is forwarded to it as `--cpus`, with a matching `--threads` for `llama-server`; an unconstrained daemon starts an unconstrained container, and `LLAMA_ARG_THREADS` still wins. ## Customizing the gateway The example only publishes Caddy's port. Add authentication and TLS to the [`Caddyfile`](../examples/compose/Caddyfile) before exposing it outside a trusted network, or have the daemon do both itself (`LLMMAN_API_KEYS`, `LLMMAN_TLS_CERT`/`LLMMAN_TLS_KEY`; see [api.md](api.md#authentication)).