Table of Contents
Root³ Solutions LibreChat Deployment Guide
Stack: LibreChat + LM Studio (Qwen3 27B) + ComfyUI MCP + Admin-Panel Host: 192.168.1.203 — Nobara Linux, Podman (kein Docker) Installiert: 2026-10-19 / finalisiert 2026-10-20 URLs: App http://192.168.1.203:3080 — Admin-Panel http://192.168.1.203:3090 Konto: info@root3.de (ADMIN — erster registrierter Nutzer)
1. Verzeichnisstruktur
Ein Ordner, alles drin. Alle Secrets liegen NUR in .env — compose.yaml referenziert sie als ${VARS}, nie hartkodiert [1].
~/librechat/ ├── compose.yaml # Podman Compose — 3 Services (api + mongodb + admin-panel) ├── librechat.yaml # LibreChat-Konfig — Endpoints, MCP, Interface ├── boot-librechat.sh # Login-Autostart-Skript (LLM zuerst) ├── .env # ALLE Secrets + Umgebungsvariablen (in api und Panel eingebunden) ├── root_solutions_logo.svg # Dein Logo — ersetzt die eingebaute logo.svg ├── index.html # Gepatchtes LibreChat-Index (linkt custom.css) └── custom.css # Logo-Größe + Zentrierung Override
2. compose.yaml (Komplett)
Drei Services: LibreChat-API, MongoDB und das separate Admin-Panel [1]. Keine Secrets in dieser Datei — nur eine ${VARIABLE}-Referenz für das Panel-Session-Secret, die podman-compose bei der Container-Erstellung aus .env auflöst (verifiziert funcionando).
services: api: image: ghcr.io/danny-avila/librechat:latest container_name: librechat-app ports: - "3080:3080" depends_on: - mongodb extra_hosts: - "host.containers.internal:host-gateway" volumes: # Konfig + Branding (Read-only Bind-Mounts) - ./librechat.yaml:/app/librechat.yaml:ro - ./root_solutions_logo.svg:/app/client/dist/assets/logo.svg:ro - ./index.html:/app/client/dist/index.html:ro - ./custom.css:/app/client/dist/custom.css:ro # Dauerhafte Daten (Named Volumes — überleben Container-Neuanlage) - librechat-images:/app/client/public/images - librechat-uploads:/app/api/data/uploads - librechat-logs:/app/api/logs # Alle Secrets/Env — einzige Wahrheit ist ./.env - ./.env:/app/.env:ro environment: - HOST=0.0.0.0 - PORT=3080 - MONGO_URI=mongodb://mongodb:27017/LibreChat - ALLOW_REGISTRATION=true restart: "no" mongodb: image: docker.io/library/mongo:latest container_name: librechat-db volumes: - librechat-db-data:/data/db restart: "no" admin-panel: image: registry.librechat.ai/librechat-ai/librechat-admin-panel:latest container_name: librechat-admin ports: - "3090:3000" depends_on: - api extra_hosts: - "host.containers.internal:host-gateway" volumes: - ./.env:/app/.env:ro environment: - PORT=3000 - SESSION_SECRET=${ADMIN_PANEL_SESSION_SECRET} - API_SERVER_URL=http://librechat-app:3080 - VITE_API_BASE_URL=http://192.168.1.203:3080 restart: "no" volumes: librechat-db-data: name: librechat-db-data librechat-images: name: librechat-images librechat-uploads: name: librechat-uploads librechat-logs: name: librechat-logs
Wichtige Design-Entscheidungen:
- restart: “no” überall — Start wird vom Boot-Skript gesteuert; keine unerwarteten Auto-Neustarts (passt zu deinem open-webui-Pattern)
- host.containers.internal:host-gateway — Container erreichen LM Studio (:1234) und ComfyUI (:8188) auf dem Host per Namen, ohne harte LAN-IP
- Named Volumes für alle dauerhaften Daten — Löschen/Erneuern von Container berührt nie Chat-Verlauf, Uploads oder Datenbank [2]
- Vollqualifizierte Image-Namen (docker.io/library/mongo:latest) — verhindert den interaktiven “Image auswählen”-Prompt in unbeaufsichtigten Skripten
- Das Admin-Panel hat eine eigene URL (:3090), ist kein Tab in der App — das ist LibreChars offizielle Architektur [1]; Nutzer-Verwaltung existiert nur dort (oder via Registrierung bzw. den offiziellen create-user/delete-user-CLI-Skripts)
3. .env-Datei (Komplett — ALLE Secrets hier)
# ~/librechat/.env HOST=0.0.0.0 PORT=3080 MONGO_URI=mongodb://mongodb:27017/LibreChat ALLOW_REGISTRATION=true JWT_SECRET=super_secret_token_string_generation_12345 REFRESH_TOKEN_SECRET=super_secret_refresh_token_string_54321 # ⚠️ DIE Variable, die dieser Image-Build für Sign-in tatsächlich liest (siehe 8a): JWT_REFRESH_SECRET=super_secret_refresh_token_string_54321 ADMIN_PANEL_SESSION_SECRET=08513016b4e0f9fc9d3466f4d10e740efdf490c6d2fae7bc86536b2bb7fc5ea3 ADMIN_PANEL_PORT=3090 ADMIN_PANEL_URL=http://192.168.1.203:3090
Hinweise:
- Wird in BEIDE Container (api und admin-panel) eingebunden (.env:/app/.env:ro) — der Auth-Code der api liest Secrets aus dieser Datei [3]
- ALLOW_REGISTRATION=true schaltet den Sign-up-Link frei; nach Konto-Anlage auf false stellen, um die Tür zu verschließen (Nutzer können weiterhin über Panel/CLI angelegt werden)
- ADMIN_PANEL_PORT / ADMIN_PANEL_URL werden aktuell von keinem Service gelesen — als Absichtsdokumentation behalten
4. librechat.yaml (Komplett)
version: 1.1.2 interface: privacyPolicy: externalUrl: 'https://yourcompany.com' openNewTab: true termsOfService: externalUrl: 'https://yourcompany.com' openNewTab: true endpoints: custom: - name: "LM Studio" # host.containers.internal = der Host, vom Container aus gesehen baseURL: "http://host.containers.internal:1234/v1" apiKey: "lm-studio" models: fetch: true # Live-Modellliste aus LM Studio default: ["qwen/qwen3.8-27b"] # deine tatsächliche Modell-ID titleConvo: true summarize: false mcpServers: comfyui: type: stdio command: npx args: - "-y" - "comfyui-mcp" # echtes npm-Paket (Oktober 2026 verifiziert) - "--comfyui-url" - "http://host.containers.internal:8188"
Hinweise:
- baseURL ist der korrekte Feldname (nicht “url”) [4]
- fetch: true füllt die Modell-Auswahl automatisch aus dem, was in LM Studio geladen ist
- “mcp-server-comfyui” existiert NICHT auf npm — comfyui-mcp ist das echte Paket, unterstützt Remote-ComfyUI via –comfyui-url [5]
- Der erste MCP-Aufruf braucht Internet im Container (npx-Download); spätere Aufrufe sind gecacht
5. Logo-Größe (custom.css)
LibreChat rendert logo.svg in fester kleiner Größe, ohne Config-Schalter. Lösung: gepatchtes index.html lädt ein zusätzliches Stylesheet, das die img-Regel überschreibt [6].
5a. So wurde es eingerichtet
# 1) Die echte index.html aus dem Container holen (während er läuft) podman exec librechat-app cat /app/client/dist/index.html > ~/librechat/index.html # 2) Einen Link-Tag in <head> einfügen sed -i 's|</head>|<link rel="stylesheet" href="/custom.css"></head>|' ~/librechat/index.html # 3) Das Override selbst (Datei: ~/librechat/custom.css) cat > ~/librechat/custom.css <<'EOF' img[src*="logo.svg"] { height: 140px !important; width: auto !important; display: block !important; margin-left: auto !important; margin-right: auto !important; } EOF
5b. Nachjustierung
px-Wert in ~/librechat/custom.css ändern → Browser hart neu laden (Strg+Shift+R). Bind-Mount liest live — kein Container-Neuaufbau nötig.
⚠️ Nach jedem LibreChat-Image-Update index.html aus dem frischen Container neu extrahieren und die sed-Zeile erneut anwenden, dann einmal down/up (sonst geht das Logo-Patch mit dem neuen Image verloren).
6. boot-librechat.sh (Finale Version)
Läuft über Nobara Login Scripts (System-Einstellungen → Autostart → Login-Skripte). Reihenfolge wie dein bestehendes start-ai-new.sh: LLM zuerst, dann alle drei Container, dann Health-Check. Idempotent — mehrfaches Auslösen beim Login ist sicher.
#!/bin/bash # boot-librechat.sh — startet LibreChat-Stack nach dem Login (LM Studio zuerst) LOG=/var/log/librechat-boot.log exec >> "$LOG" 2>&1 echo "=== $(date) librechat-boot ===" PATH="$HOME/.local/bin:$PATH" MODEL="qwen/qwen3.8-27b" # --- 1. Läuft der LM-Studio-Server? ----------------------------------- if ! curl -s --connect-timeout 2 http://localhost:1234/v1/models > /dev/null; then echo "⏳ LM Studio nicht erreichbar — Server wird gestartet..." lms server start || echo "⚠️ lms server start fehlgeschlagen." for i in $(seq 1 15); do curl -s --connect-timeout 2 http://localhost:1234/v1/models > /dev/null && break sleep 2 done fi # --- 2. Ist ein Modell geladen? (no-op, falls schon im RAM) ---------- echo "⏳ Modell wird in LM Studio geladen..." lms load "$MODEL" || echo "⚠️ lms load fehlgeschlagen." sleep 5 # --- 3. Alle LibreChat-Container starten ------------------------------- if podman ps -a --filter "name=librechat-app" --format '{{.Names}}' | grep -q librechat-app; then echo "📦 LibreChat-Container werden gestartet..." podman start librechat-app librechat-db librechat-admin 2>&1 else echo "⚠️ Container nicht gefunden — erst via Compose anlegen..." cd ~/librechat && podman-compose --in-pod true up -d \ || { echo "❌ Compose fehlgeschlagen."; exit 1; } fi # --- 4. Health-Check --------------------------------------------------- for i in $(seq 1 10); do if curl -s --connect-timeout 2 http://localhost:3080/ > /dev/null; then echo "✅ LibreChat-API ist erreichbar." break fi [ "$i" -eq 10 ] && { echo "❌ API tot — letzte 30 Log-Zeilen:"; podman logs --tail 30 librechat-app; exit 1; } sleep 5 done echo "=== $(date) fertig ==="
Autostart-Einrichtung (einmalig, erledigt):
- Nobara System-Einstellungen → Autostart → + Neu hinzufügen → Login-Skript → ~/librechat/boot-librechat.sh → Ja sagen für Ausführbarkeit
- Zum Deaktivieren: Eintrag löschen, oder rm ~/librechat/boot-librechat.sh
Log-Datei: /var/log/librechat-boot.log — tail -f /var/log/librechat-boot.log
7. Befehlsreferenz
| Aktion | Befehl |
|---|---|
| — | — |
| Stack starten (manuell) | podman start librechat-app librechat-db librechat-admin |
| Stack stoppen | podman stop librechat-app librechat-db librechat-admin |
| up/down der Container nach yaml-/env-Änderung | cd ~/librechat && podman-compose –in-pod true down && podman-compose –in-pod true up -d |
| LibreChat-Image aktualisieren (behalten alle Daten) | cd ~/librechat && podman-compose –in-pod true down && podman pull ghcr.io/danny-avila/librechat:latest && podman-compose –in-pod true up -d |
| — | — |
| App-Logs ansehen | podman logs –tail 100 librechat-app |
| Mongo-Logs ansehen | podman logs –tail 50 librechat-db |
| Panel-Logs ansehen | podman logs –tail 50 librechat-admin |
| Boot-Log ansehen | tail -f /var/log/librechat-boot.log |
| Pod-Status prüfen | podman pod ps |
| Stack entfernen, DATEN behalten | cd ~/librechat && podman-compose –in-pod true down |
| Komplett löschen inkl. Daten | oben + podman volume rm librechat-db-data librechat-images librechat-uploads librechat-logs |
| — | — |
| Alle Nutzer + Rollen auflisten | podman exec librechat-db mongosh –quiet –eval 'db.getSiblingDB(“LibreChat”).users.find({}, {email:1, roles:1}).toArray()' |
| Live-Modelle von LM Studio prüfen | curl -s http://localhost:1234/v1/models |
Hinweise:
- “up/down nach yaml/env-Änderung” = wendet deine Config-Änderungen an (das ist deine Zeile — Achte auf das korrekte Bindestrich in -in-pod)
- “Image aktualisieren” holt zusätzlich die neue Version; danach index.html fürs Logo neu extrahieren (Abschnitt 5b)
- Alle down/rm-Befehle berühren Named Volumes nie — Daten sind sicher
8. Fehlerbehebung
8a. Login liefert 500 "secretOrPrivateKey must have a value"
Ursache: Dieser Image-Build signiert Refresh-Tokens mit process.env.JWT_REFRESH_SECRET, nicht REFRESH_TOKEN_SECRET (bestätigt in node_modules/@librechat/data-schemas/dist/index.mjs:5989). Registrierung funktionierte, weil dort kein Token ausgestellt wird. Lösung: JWT_REFRESH_SECRET=<Wert> in .env + Neuaufbau. ✅ Angewendet.
8b. "Image auswählen"-Prompt hängt Skripte auf
Ursache: Nackte Image-Namen lösen Podmans interaktiven Registry-Auswahlmenü aus; ohne TTY blockt es ewig. Lösung: Vollqualifizierte Namen in compose.yaml (docker.io/library/mongo:latest, ghcr.io/danny-avila/librechat:latest). ✅ Angewendet.
8c. Code-Interpreter-Image 403 Forbidden
Ursache: ghcr.io/danny-avila/code-interpreter:latest existiert nicht mehr im Registry; die offizielle Compose-Datei liefert es auch nicht mehr [1]. Lösung: Service entfernt — für Chat + ComfyUI-MCP nicht nötig. ✅ Angewendet.
8d. Logo auf der Login-Seite zu klein
Ursache: Eingebaute CSS skaliert logo.svg fix; kein Config-Schalter im interface-Objekt vorhanden. Lösung: Gepatchtes index.html → custom.css → img[src*=“logo.svg”]-Override, 140px + zentriert. ✅ Im Browser verifiziert.
8e. podman-compose --pod wird nicht erkannt
Ursache: Das dnf-Paket (v1.6.0) ist containers/podman-compose v1.x — anderer Flag-Name als die pipx-Version. Lösung: –in-pod true vor dem Subkommando verwenden: podman-compose –in-pod true up -d. ✅ Angewendet.
8f. "agent_id is required in request body"
Ursache: Nachricht wurde gesendet, bevor im Modell-Picker der LM-Studio-Endpoint ausgewählt war — Anfrage lief an den Agents-Endpunkt. Lösung: Neue Unterhaltung, Modell zuerst explizit wählen. ✅ Behoben.
8g. Admin-Panel-Image 403 auf ghcr
Ursache: ghcr.io/danny-avila/librechat-admin-panel:latest existiert dort nicht; korrektes Registry laut offizieller Compose ist registry.librechat.ai/librechat-ai/librechat-admin-panel:latest [1]. Lösung: Image-Referenz korrigiert. ✅ Container läuft, Panel erreichbar unter :3090.
8h. Logs zeigen "OpenID check failed: 500 .../openid/check"
Ursache: Bekannter Upstream-Bug — LibreChat-Issue #14504, gefixt in PR #14507. Der Maintainer bestätigt: Log-Rauschen, NICHT der Login-Blocker (das Panel behandelt jede nicht-ok-Antwort als “SSO unavailable” und fällt auf E-Mail/Passwort zurück). Aktion: Keine — ignorieren, bis ein Image-Update den Fix enthält.
8i. Admin-Panel-Login: Formular wird abgeschickt, passiert nichts
⚠️ OFFENER PUNKT. API-Logs zeigen wiederholt [Login] [Login successful] [info@root3.de] — Zugangsdaten akzeptiert, Auth funktioniert; das Panel stellt aber keine Browser-Session auf. Verdacht Nr. 1: Session-Cookies mit Secure-Flag über plain HTTP (Kandidaten: SESSION_COOKIE_SECURE=false / ADMIN_PANEL_SESSION_COOKIE_SECURE=false in .env) oder Panel-internes Session-Wiring. Zweite offene Prüfung: users.find({}, {email:1, roles:1}) — sicherstellen, dass genau ein Nutzer die ADMIN-Rolle trägt (laut #14504-Thread bekommt nur der erste registrierte Nutzer sie). Status: ungelöst — nächster Schritt: Network-Tab auf :3090/login (fehlgeschlagene Anfrage + Statuscode) plus Logs von librechat-admin während eines Login-Versuchs.
9. Statusübersicht
| Komponente | Status | Hinweis |
|---|---|---|
| — | — | — |
| Logo (groß + zentriert) | ✅ im Browser verifiziert | custom.css, 140px |
| Auth: Registrierung + Login | ✅ funktioniert | JWT_REFRESH_SECRET-Fix |
| LM-Studio-Chat | ✅ “Hello!”-Antwort bestätigt | Qwen3 27B via fetch:true |
| — | — | — |
| ComfyUI MCP-Server | ✅ “running on stdio” in Logs | comfyui-mcp-Paket |
| Admin-Konto | ✅ info@root3.de (erster Nutzer = ADMIN) | Panel hat eigene URL :3090 |
| Admin-Panel-Service | ✅ läuft, erreichbar unter :3090 | Login noch offen (8i) |
| — | — | — |
| Autostart (LLM zuerst) | ✅ Nobara Login-Skript | /var/log/librechat-boot.log |
| Datenbeständigkeit | ✅ Named Volumes | Überleben Neuanlage/Updates |
| Podman-Desktop-Gruppierung | ✅ pod_librechat, 3 Container | –in-pod true |
| — | — | — |
| ComfyUI-Bildgenerierung End-to-End | ⏳ noch nicht getestet | letzter offener Funktionstest |
