LLM Proxy¶
Klangk runs an nginx reverse proxy in front of the FastAPI backend. Nginx serves the Flutter web UI, proxies API and WebSocket traffic to uvicorn, proxies hosted app URLs directly to container ports (keeping the Python backend out of that hot path), and provides the LLM proxy described below. Using nginx also enables auth_request-based JWT validation on container-to-host endpoints without adding middleware overhead to every backend request.
Pi containers access the LLM via the LLM proxy, an nginx location that proxies /llm-proxy/ requests to ${KLANGK_LLM_BASE_URL}. This is required because:
- Pi is inside a container, LLM is on the host: Pi containers can't reach
localhost:11434(self-hosted Ollama) directly. They usehost.containers.internalto reach the host, but the host's nginx serves the proxy. - API key security: The API key is sent in a request header by the nginx proxy rather than being baked into the container image or passed as an env var. The container's
models.jsoncontains only the proxy URL (no real API key). - No per-container LLM config: The backend injects
KLANGK_LLM_PROXY_URL=http://host.containers.internal:<nginx_port>/llm-proxyinto each container.setup_clankers.pyuses this to write Pi'smodels.jsonwith the proxy URL and the workspace JWT as the API key (nginx validates the JWT viaauth_requestbefore replacing it with the real API key).KLANGK_LLM_BASE_URLis only used by nginx itself.
The nginx config is generated by scripts/nginx.sh and includes:
location /llm-proxy/ {
auth_request /auth/verify-workspace-token;
proxy_pass $KLANGK_LLM_BASE_URL/;
proxy_set_header Authorization "Bearer $KLANGK_LLM_API_KEY";
proxy_ssl_server_name on;
}
In CI, devenv processes up -d starts nginx before E2E tests run.