From 7a5fd8445564c812f552cdc95121994cb064a6b0 Mon Sep 17 00:00:00 2001 From: Jim Schaff Date: Wed, 12 Aug 2026 14:46:04 -0400 Subject: [PATCH] fix(k8s): make LiteLLM emit https URLs behind the ingress /kartik/ui redirected to http:///kartik/ui/ instead of https. Browsers recovered on a second hop, but the first one was plaintext. LiteLLM takes uvicorn's defaults, so ProxyHeadersMiddleware is installed (proxy_headers=True) but only trusts 127.0.0.1 -- uvicorn falls back to FORWARDED_ALLOW_IPS or "127.0.0.1" (uvicorn/config.py:357). nginx connects from a pod IP, so X-Forwarded-Proto was discarded and the request scheme stayed http, which is what Starlette used to build the redirect. "*" is safe here: the Service is ClusterIP, so nothing outside the cluster can reach the pod directly to forge the header, and nginx overwrites it per request. Dev only, since prod and local don't expose the proxy through an ingress. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_0174W6CHp7FMt7c9sKdBhbp1 --- kustomize/config/vcell-ai-rke-dev/litellm.env | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/kustomize/config/vcell-ai-rke-dev/litellm.env b/kustomize/config/vcell-ai-rke-dev/litellm.env index 0fbb546..8919a2f 100644 --- a/kustomize/config/vcell-ai-rke-dev/litellm.env +++ b/kustomize/config/vcell-ai-rke-dev/litellm.env @@ -23,3 +23,13 @@ LANGFUSE_HOST=https://cloud.langfuse.com # rewrite-target and does NOT change route matching: the backend's in-cluster # calls to http://litellm:4000/v1/... keep working unprefixed. SERVER_ROOT_PATH=/kartik + +# Trust the ingress controller's X-Forwarded-Proto so generated URLs use https. +# LiteLLM takes uvicorn's defaults, which install ProxyHeadersMiddleware but +# only trust 127.0.0.1 (uvicorn/config.py: FORWARDED_ALLOW_IPS default). nginx +# connects from a pod IP, so the header was ignored and /kartik/ui redirected to +# an http:// URL. Browsers recovered via a second hop, but it was a plaintext +# one. "*" is safe here because the Service is ClusterIP -- nothing outside the +# cluster can reach the pod directly to forge the header, and nginx overwrites +# it on every request. +FORWARDED_ALLOW_IPS=*