Skip to content

feat(k8s): make LiteLLM's URL prefix configurable via SERVER_ROOT_PATH - #95

Merged
jcschaff merged 1 commit into
mainfrom
feat/litellm-server-root-path
Aug 12, 2026
Merged

feat(k8s): make LiteLLM's URL prefix configurable via SERVER_ROOT_PATH#95
jcschaff merged 1 commit into
mainfrom
feat/litellm-server-root-path

Conversation

@jcschaff

Copy link
Copy Markdown
Member

Follow-up to #93 / #94. The proxy is served at /kartik on dev, but LiteLLM built its URLs from its own root, so /kartik/ui redirected to an absolute http://<host>/ui/ — escaping the prefix, landing on the Next.js frontend, and dead-ending in Auth0. SERVER_ROOT_PATH makes it prefix-aware.

Where it lives. config/*/litellm.env, not base/ — the prefix is a property of how each environment exposes the proxy (/kartik on dev; unset, i.e. root, for prod and local). It flows through the existing litellm-config ConfigMap that the deployment already consumes via envFrom, and since configMapGenerator hashes the ConfigMap name, the change rolls the pod on its own with no base edit.

Why this doesn't break in-cluster callers. SERVER_ROOT_PATH is handed to FastAPI as root_path (proxy_server.py:1347) — the "reverse proxy strips the prefix" contract, which matches the ingress rewrite-target: /$2 we already have. root_path affects generated URLs and docs, not route matching, so the backend keeps calling http://litellm:4000/v1/... and /user/* unprefixed (backend/app/core/config.py:44).

The one real behavioral change: normalize_route_for_root_path (user_api_key_auth.py:630) returns None for unprefixed requests once a root path is set, so those no longer match the pass-through route special case. We don't use LiteLLM's pass-through routes, so this is inert here.

Caveat on the UI: at startup LiteLLM rewrites its bundled UI assets in place to embed the prefix, and skips that with a warning if the directory isn't writable (proxy_server.py:1885-1895). Our container has no readOnlyRootFilesystem, so it should apply — worth confirming /kartik/ui actually renders after rollout.

Config-only, no image bump.

🤖 Generated with Claude Code

https://claude.ai/code/session_0174W6CHp7FMt7c9sKdBhbp1

The proxy is served at /kartik on dev, but LiteLLM built its URLs from its own
root: /kartik/ui redirected to an absolute http://<host>/ui/, escaping the
prefix and landing on the Next.js frontend (then Auth0, then a 400). Setting
SERVER_ROOT_PATH makes it prefix-aware, so the admin UI is reachable.

Set per-environment in config/*/litellm.env rather than base/, since the prefix
is a property of how each environment exposes the proxy: /kartik on dev, unset
(root) for prod and local. It flows through the existing litellm-config
ConfigMap, which the deployment already consumes via envFrom -- and because
configMapGenerator hashes the name, the change rolls the pod automatically.

Safe for in-cluster callers: SERVER_ROOT_PATH is passed to FastAPI as root_path
(proxy_server.py:1347), which only affects generated URLs, not route matching,
and matches the ingress rewrite-target that already strips the prefix. The
backend keeps calling http://litellm:4000/v1/... and /user/* unprefixed. The
one behavioral change is in user_api_key_auth.py:630, where unprefixed requests
no longer match the pass-through-route special case -- unused here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0174W6CHp7FMt7c9sKdBhbp1
@jcschaff
jcschaff merged commit 16b61db into main Aug 12, 2026
1 check passed
@jcschaff
jcschaff deleted the feat/litellm-server-root-path branch August 12, 2026 18:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant