Server deployment and security
By default dynalm serve binds 127.0.0.1 and needs no authentication. To serve other machines on a trusted network, bind a non-loopback address and set an API key with --api-key-file; DynaLM refuses to start without one. DynaLM has no TLS and no per-client rate limiting, so it must not be exposed to the public internet directly — place an authenticating reverse proxy in front.
Supported deployment modes
| Mode | Bind | Authentication | Status |
|---|---|---|---|
| Local (one user, one machine) | 127.0.0.1 (default) | none needed | Supported |
| Trusted LAN or service | non-loopback --host | required: --api-key-file or DYNALM_API_KEY | Supported |
| Behind an authenticating gateway | non-loopback with --allow-unauthenticated | delegated to the gateway (TLS, auth, rate limits) | Supported only when only the gateway can reach DynaLM |
| Public internet, directly | — | — | Not supported |
Serve on a local network with an API key
openssl rand -hex 32 > ~/.dynalm/api-key
dynalm serve qwen2.5:1.5b --host 0.0.0.0 --api-key-file ~/.dynalm/api-key
Clients send Authorization: Bearer <key>. Every endpoint except GET /health requires it; the key is compared in constant time and never logged.
Built-in protections
- Browser attacks on the local API: POST bodies must be
application/json(415 otherwise) and CORS preflights are never answered, so a web page cannot drive the API cross-origin. - DNS rebinding: on a loopback bind, the
Hostheader must belocalhost,127.xor[::1](403 otherwise). - Resource limits: 8 MiB body limit, validated
max_tokens, at most--max-activeconcurrent completions (then 503 withRetry-After), a 600 s default request timeout, and prompt length checked against KV capacity. - Untrusted model files: the GGUF and SafeTensors parsers bounds-check sizes and offsets and are mutation-fuzzed in CI under ASan and UBSan. Chat templates in model metadata are never executed.
- Shutdown endpoint:
POST /admin/shutdownis loopback-only and can be turned off with--disable-admin.
Run in Docker
docker run --rm -d -p 127.0.0.1:8000:8000 -v "$PWD/models:/models" \
ghcr.io/dynalm-project/dynalm:cpu serve /models/qwen3-4b.gguf --allow-unauthenticated
Caution Inside a container the server binds a non-loopback address, which is why the example uses --allow-unauthenticated and publishes the port on 127.0.0.1 only. If you publish it more widely, use --api-key-file or a gateway instead.
Health checks and monitoring
GET /health returns 200 when ready and 503 while draining, which suits container liveness probes. GET /metrics exposes Prometheus counters and histograms for requests, time to first token, inter-token latency, tokens, KV block use, prefix-cache hits and resident memory. On shutdown the server stops accepting work and finishes in-flight requests for up to --shutdown-timeout seconds (default 30).
Frequently asked questions
Can I expose DynaLM to the internet?
Not directly. Put a reverse proxy that provides TLS, authentication and rate limiting in front, and make sure only the proxy can reach DynaLM.
How do I report a security issue?
Follow the process in the repository’s SECURITY.md rather than opening a public issue.
Source: docs/security.md (opens in a new tab), docs/deployment.md (opens in a new tab), SECURITY.md (opens in a new tab)