What's in this release
Olla is a high-performance proxy and load balancer for LLM infrastructure.
Quick Start
# Docker
docker pull ghcr.io/thushan/olla:v0.0.29
# Binary (see assets below)
./olla --config config.yamlWhat's New in v0.0.29
Admin Dashboard
- New embedded, read-only admin dashboard at
/internal/ui/- Overview (fleet status, success rate, latency, live requests-per-second sparkline), Endpoints (per-endpoint health, priority, latency, model count) and Models (inventory grouped by family, with hosting endpoints). Built in Svelte 5 + TailwindCSS, polled (not pushed) against the existing/internal/status*JSON, and served from the same listener as the proxy - no second port (#205). - The dashboard has no authentication. Access is controlled by a new
dashboard.access_policyconfig block (allowed_cidrs+allowed_hosts), loopback-only by default. The published Docker image ships withallowed_cidrspre-widened to the RFC1918 ranges sodocker run -p 40114:40114 ghcr.io/thushan/olla:latestgives you a working dashboard with no config mount - which also means the container is reachable from anyone else on the same LAN through that published port (#213). See the Admin Dashboard docs for the full security model. - A binary built without
make build-web(e.g. plaingo buildorgo install) now logs a clear startup warning and serves503at/internal/ui/instead of a silent placeholder (#213).
Observability
- Native
GET /internal/metricsin Prometheus text format, built from the same data as/internal/statusand/internal/stats/models- no external exporter needed for core proxy monitoring. Thanks to @Puupuls for the contribution (#188). /internal/status,/internal/status/endpointsand/internal/status/modelsnow emit a weakETag, so polling clients (including the new dashboard) can useIf-None-Matchand get304s instead of re-fetching the full payload (#205, #213).- Sticky-session and routing decisions are now in the structured "Request completed" log line (
sticky_outcome, routing strategy/action/reason,provider_model, translator fallback reason), not just response headers. Addresses issue #178 (#182). - Successful proxy requests log at
Infoagain in the access log; a prior regression had silently demoted them toDebug(#211).
Reliability
- A request landing on an endpoint whose circuit breaker is open now fails over to the next available endpoint instead of failing outright. The endpoint is dropped from that request's candidate list only - its persisted health is left alone, since an open breaker already reflects accumulated failure state and demoting health on top of it isn't the retry path's job (#213).
- Strict routing no longer lets an unroutable
model_aliasesentry silently proxy to the wrong backend: a request for an alias whose target model exists on no endpoint now fails fast with404/503androuting_action: rejected, matching how unknown models are already handled. Reported by @skaravos (#197, issue #191). config/models.yamlnow actually parses. It used\dinside double-quoted YAML scalars, which is invalid YAML, so the file has never loaded on any install - the failure was swallowed and Olla silently fell back to embedded defaults, discarding any customisation with no diagnostic. Reported by @billford (#206, issue #204).- New
--validate-configflag checks configuration and provider profiles without starting the server, with a pass/warn/fail report and exit codes (#210). logging.levelin config is now actually applied to the runtime logger, instead of being parsed and ignored (#209).
Model Catalog
- Refreshed the built-in model catalog for 2026: recognises more families and variants (GPT-OSS, GLM, Kimi, Granite, Nemotron, EXAONE, Hunyuan, MiniMax, OLMo, InternLM, SmolLM, Command-R, Forge) and MXFP4/NVFP4 quantisation (#207).
- Wired
model_extraction.family_aliasesandspecial_rules.preserve_familyinto the family-extraction pipeline - both were parsed but previously had no effect. Fixes Kimi-K2 being misclassified underdeepseek(shared GGUF architecture lineage) (#208).
Security & Startup
- An endpoint URL with embedded
user:pass@hostcredentials now fails startup instead of loading silently and leaking the credentials into every status/dashboard JSON response. The boot error rewrites the URL into a ready-to-pasteauth:block with placeholders, so the fix doesn't require re-typing the real credentials (#213). - The
idandurlfields on/internal/statusand/internal/status/endpointsare now derived from a sanitised URL (userinfo, query and fragment stripped) rather than echoing the raw configured URL (#213). /internal/statusno longer reports"status": "critical"on a healthy fresh boot with no traffic yet. A newsystem.has_trafficboolean lets clients branch on the no-traffic state directly instead of parsing thesuccess_ratestring (#213).
Docker & Release
- Streamlined the container image and switched to
.dockerignorefor a smaller, more predictable build context (#213). - Added a release dry-run validation step to the release pipeline (#213).
Breaking Changes
- Userinfo URLs:
- url: "http://user:pass@host:8080"now fails startup. Move credentials into anauth:block:- url: "http://host:8080" auth: type: basic username: user password: pass
- Status
id/urlfields: now derived from a sanitised URL rather than the raw config value. Bookmarked dashboard deep-links to a specific endpoint will change once after upgrading. Clients comparingurlfor identity should switch toid. - Zero-traffic status: a fresh boot with all endpoints healthy no longer reports
"critical". Checksystem.has_trafficif you branch on traffic state. - Strict routing on unroutable aliases:
/olla/proxy/with zero healthy endpoints now returns503instead of502. Update any monitor keyed on that status code. owned_byin converted model listings: the shared organisation-extraction logic used by the vLLM, vLLM-MLX, SGLang, llama.cpp, LMDeploy and Lemonade converters now also matches a hyphenated leading segment (e.g.Qwen2.5-7B→owned_by: "Qwen2.5") rather than falling through to a generic default. Treatowned_byas a best-effort label, not a canonical identifier.
Acknowledgements
Thanks to everyone who contributed to this release:
- @Puupuls - contributed the native
GET /internal/metricsPrometheus endpoint (#188). - @skaravos - reported the strict-routing alias bypass (issue #191).
- @billford - reported the
config/models.yamlparse failure (issue #204). - @sg-shag - reported the missing sticky-session/routing decision logging (issue #178).
Full Changelog: v0.0.28...v0.0.29
Documentation: thushan.github.io/olla | Issues: github.com/thushan/olla/issues