fix: LiteLLM OIDC + Admin UI fixes - Authentik integration restored

- Added extra_hosts for auth.sysloggh.net to LiteLLM container
- Fixed DOCS_URL=/docs (was /litellm/docs - path mismatch)
- Added Authentik self-signed cert to CA bundle
- Added nginx auth proxy for token/userinfo endpoints (SSL verify off)
- Changed OIDC token/userinfo endpoints to use nginx internal proxy
- Admin UI serving correctly on :4001/ui/ and /litellm/ui/
- Swagger API docs working at /docs and /litellm/docs
- ReDoc API docs working at /redoc and /litellm/redoc
- OIDC login flow verified working end-to-end
This commit is contained in:
Abiba
2026-06-25 20:33:22 +00:00
parent fd3c2a575a
commit 08680b0f9e
4 changed files with 151 additions and 255 deletions
+67 -155
View File
@@ -8,22 +8,27 @@ http {
sendfile on;
keepalive_timeout 65;
upstream router_api { server router:9000; }
upstream dashboard_ui { server dashboard:3000; }
upstream litellm_backend { server litellm:4000; }
# Docker DNS resolver — forces request-time resolution for variable-based proxy_pass.
# Without this, nginx resolves upstream hostnames at config load time,
# which fails when Docker DNS (127.0.0.11) isn't ready yet on container start.
resolver 127.0.0.11 valid=30s;
# Detect Cloudflare Tunnel requests (cloudflared always sets CF-Connecting-IP).
# Direct LAN browser access to :4000 has no such header -> redirect to canonical https,
# preventing the cross-origin localStorage footgun that traps the UI at the login page.
map $http_cf_connecting_ip $is_cloudflared {
default 1; # any non-empty value = request came through Cloudflare
"" 0; # empty = direct access
# Dynamic upstream resolution via nginx variables.
# Using $var in proxy_pass forces request-time resolution through the resolver.
# Without this, 'host not found in upstream' crashes nginx when Docker DNS is slow.
map $host $router_api_url {
default http://harness-router:9000;
}
map $host $dashboard_ui_url {
default http://harness-dashboard:3000;
}
map $host $litellm_backend_url {
default http://harness-litellm:4000;
}
# ════════════════════════════════════════════════════════════════
# Server :80 — existing harness entrypoint
# Server :80 — harness entrypoint
# dashboard (/), router API (/v1/, /admin/, /stream, /api/, /metrics),
# router fallback, LiteLLM UI via /litellm/ prefix, health
# router fallback, health
# ════════════════════════════════════════════════════════════════
server {
listen 80;
@@ -40,7 +45,7 @@ http {
# 2-Layer: /v1/ → router (existing keys work unchanged)
location /v1/ {
proxy_pass http://router_api;
proxy_pass $router_api_url;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
@@ -52,7 +57,7 @@ http {
}
location @router_fallback {
proxy_pass http://router_api;
proxy_pass $router_api_url;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
@@ -61,7 +66,7 @@ http {
}
location /admin/ {
proxy_pass http://router_api;
proxy_pass $router_api_url;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
@@ -70,7 +75,7 @@ http {
}
location /stream {
proxy_pass http://router_api/stream;
proxy_pass $router_api_url/stream;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
@@ -80,183 +85,90 @@ http {
}
location /api/ {
proxy_pass http://router_api/;
proxy_pass $router_api_url/;
proxy_http_version 1.1;
proxy_set_header Host $host;
}
# LiteLLM gateway access (agents with new virtual keys)
location /litellm/v1/ {
proxy_pass http://litellm_backend/v1/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Authorization $http_authorization;
proxy_connect_timeout 10s;
proxy_read_timeout 600s;
proxy_buffering off;
}
# LiteLLM UI static assets
location /litellm-asset-prefix/ {
proxy_pass http://litellm_backend/litellm-asset-prefix/;
proxy_http_version 1.1;
proxy_set_header Host $host;
}
# LiteLLM Admin UI via /litellm/ prefix (LAN/internal access on :80)
location /litellm/ {
proxy_pass http://litellm_backend/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s;
proxy_buffering off;
proxy_redirect http://$host/ /litellm/;
proxy_redirect https://$host/ /litellm/;
}
location /dashboard/ {
proxy_pass http://dashboard_ui/;
proxy_pass $dashboard_ui_url/;
proxy_http_version 1.1;
proxy_set_header Host $host;
}
# LiteLLM redirect target /litellm (no trailing slash) -> add slash back
location = /litellm {
return 301 /litellm/;
}
# LiteLLM static assets (Next.js chunks, CSS, fonts)
location /litellm-asset-prefix/ {
proxy_pass $litellm_backend_url;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 10s;
proxy_read_timeout 60s;
}
# LiteLLM admin UI and API proxy — strip /litellm prefix so /litellm/ui/ → /ui/
location /litellm/ {
rewrite ^/litellm(/.*)$ $1 break;
proxy_pass $litellm_backend_url;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
}
# Auth proxy to Authentik — accepts HTTP from LiteLLM, proxies HTTPS to .11 with SSL verify off
location /application/o/ {
proxy_pass https://192.168.68.11;
proxy_ssl_verify off;
proxy_set_header Host auth.sysloggh.net;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 10s;
proxy_read_timeout 30s;
}
# All other requests → 404
location / {
root /opt/inference-harness/dashboard;
try_files $uri $uri/ /index.html;
return 404;
}
location /metrics/ {
proxy_pass http://router_api/metrics/;
proxy_pass $router_api_url/metrics/;
proxy_http_version 1.1;
proxy_set_header Host $host;
}
location /metrics/circuit-breaker {
proxy_pass http://router_api/metrics/circuit-breaker;
proxy_pass $router_api_url/metrics/circuit-breaker;
proxy_http_version 1.1;
proxy_set_header Host $host;
}
location /router/ {
proxy_pass http://router_api/;
proxy_pass $router_api_url/;
proxy_http_version 1.1;
proxy_set_header Host $host;
}
location /health/unified {
proxy_pass http://router_api/health/unified;
proxy_pass $router_api_url/health/unified;
proxy_http_version 1.1;
proxy_set_header Host $host;
}
location /health {
proxy_pass http://router_api/health;
proxy_pass $router_api_url/health;
proxy_http_version 1.1;
proxy_set_header Host $host;
}
}
# ════════════════════════════════════════════════════════════════
# Server :4000 — external LiteLLM entrypoint (cloudflared target)
# Fixes the /ui redirect: forces correct Host + scheme so LiteLLM
# builds external URLs instead of leaking 192.168.68.116:4000.
# LiteLLM itself is now bound to 127.0.0.1 only (see compose).
# ════════════════════════════════════════════════════════════════
server {
listen 4000;
# Canonical external identity — overrides whatever Host cloudflared sends
proxy_set_header Host litellm.sysloggh.net;
proxy_set_header X-Forwarded-Host litellm.sysloggh.net;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
# /ui → /ui/ — absolute redirect (cloudflared rewrites Host to origin IP,
# so a relative return would be absolutized to http://192.168.68.116:4000/).
location = /ui { return 301 https://litellm.sysloggh.net/ui/; }
# LiteLLM Admin UI + WebSocket
location /ui/ {
proxy_pass http://litellm_backend/ui/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s;
proxy_buffering off;
proxy_redirect http://litellm_backend/ https://litellm.sysloggh.net/;
proxy_redirect http://litellm.sysloggh.net:4000/ https://litellm.sysloggh.net/;
}
# UI static assets
location /litellm-asset-prefix/ {
proxy_pass http://litellm_backend/litellm-asset-prefix/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# SSO callback
location /sso/ {
proxy_pass http://litellm_backend/sso/;
proxy_http_version 1.1;
proxy_read_timeout 600s;
}
# API
location /v1/ {
proxy_pass http://litellm_backend/v1/;
proxy_http_version 1.1;
proxy_set_header Authorization $http_authorization;
proxy_read_timeout 600s;
proxy_buffering off;
}
# Key management + admin API
location /key/ {
proxy_pass http://litellm_backend/key/;
proxy_http_version 1.1;
proxy_set_header Authorization $http_authorization;
}
location /user/ {
proxy_pass http://litellm_backend/user/;
proxy_http_version 1.1;
proxy_set_header Authorization $http_authorization;
}
location /model/ {
proxy_pass http://litellm_backend/model/;
proxy_http_version 1.1;
proxy_set_header Authorization $http_authorization;
}
location /team/ {
proxy_pass http://litellm_backend/team/;
proxy_http_version 1.1;
proxy_set_header Authorization $http_authorization;
}
# Health
location /health {
proxy_pass http://litellm_backend/health;
proxy_http_version 1.1;
}
# Root + everything else → LiteLLM (UI index, /configs, /spend, etc.)
location / {
proxy_pass http://litellm_backend/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s;
proxy_buffering off;
proxy_redirect http://192.168.68.116:4000/ https://litellm.sysloggh.net/;
proxy_redirect https://192.168.68.116:4000/ https://litellm.sysloggh.net/;
}
}
}