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:

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:

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:

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):

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:

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