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 (no Docker) Deployed: 2026-10-19 / finalized 2026-10-20 URLs: App http://192.168.1.203:3080 — Admin Panel http://192.168.1.203:3090 Account: info@root3.de (ADMIN — first registered user)

1. Folder Structure

One folder, everything inside it. All secrets live ONLY in .env — compose.yaml references them as ${VARS}, never hardcoded [1].

~/librechat/
├── compose.yaml            # Podman Compose — 3 services (api + mongodb + admin-panel)
├── librechat.yaml          # LibreChat config — endpoints, MCP, interface
├── boot-librechat.sh       # Login autostart script (LLM-first ordering)
├── .env                    # ALL secrets + env vars (mounted into both api and panel)
├── root_solutions_logo.svg # Your logo — overwrites the built-in logo.svg
├── index.html              # Patched LibreChat index (links custom.css)
└── custom.css              # Logo size + centering override

2. compose.yaml (Complete)

Three services: LibreChat API, MongoDB, and the separate Admin Panel [1]. No secrets in this file — only one ${VAR} reference for the panel session secret, which podman-compose expands from .env at create time (verified working).

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:
      # Config + 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
      # Durable data (named volumes — survive container recreation)
      - librechat-images:/app/client/public/images
      - librechat-uploads:/app/api/data/uploads
      - librechat-logs:/app/api/logs
      # All secrets/env — single source of truth is ./.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

Key design decisions:

3. .env File (Complete — ALL Secrets Here)

# ~/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
# ⚠️ THE one this image build actually reads for sign-in (see troubleshooting 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

Notes:

4. librechat.yaml (Complete)

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 = the host machine, from inside the container
      baseURL: "http://host.containers.internal:1234/v1"
      apiKey: "lm-studio"
      models:
        fetch: true          # live model list from LM Studio
        default: ["qwen/qwen3.8-27b"]   # your actual model ID
      titleConvo: true
      summarize: false

mcpServers:
  comfyui:
    type: stdio
    command: npx
    args:
      - "-y"
      - "comfyui-mcp"        # real npm package (verified Oct 2026)
      - "--comfyui-url"
      - "http://host.containers.internal:8188"

Notes:

5. Logo Sizing (custom.css)

LibreChat renders logo.svg at a fixed small size with no config key to change it. Fix: patched index.html loads an extra stylesheet, which overrides the img rule [6].

5a. How it was set up

# 1) Copy the real index.html out of the container (while running)
podman exec librechat-app cat /app/client/dist/index.html > ~/librechat/index.html
# 2) Inject a link tag into <head>
sed -i 's|</head>|<link rel="stylesheet" href="/custom.css"></head>|' ~/librechat/index.html
# 3) The override itself (file: ~/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. Tuning

Edit the px value in ​~/librechat/custom.css → hard refresh browser (Ctrl+Shift+R). Bind mount reads live — no container recreate needed.

⚠️ After every LibreChat image update, re-extract index.html from the fresh container and re-apply the sed line, then down/up once (logo patch would otherwise revert on new images).

6. boot-librechat.sh (Final Version)

Runs via Nobara Login Scripts (System Settings → Autostart → Login Scripts). Ordering matches your existing start-ai-new.sh pattern: LLM first, then all three containers, then health check. Idempotent — safe to fire multiple times at login.

#!/bin/bash
# boot-librechat.sh — start LibreChat stack after login (LM Studio first)
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. LM Studio server up? ------------------------------------------
if ! curl -s --connect-timeout 2 http://localhost:1234/v1/models > /dev/null; then
    echo "⏳ LM Studio not responding — starting server..."
    lms server start || echo "⚠️  lms server start failed."
    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. Model loaded? (no-op if already in RAM) ------------------------
echo "⏳ Loading model into LM Studio..."
lms load "$MODEL" || echo "⚠️  lms load failed."
sleep 5
 
# --- 3. Start all LibreChat containers ---------------------------------
if podman ps -a --filter "name=librechat-app" --format '{{.Names}}' | grep -q librechat-app; then
    echo "📦 Starting LibreChat containers..."
    podman start librechat-app librechat-db librechat-admin 2>&1
else
    echo "⚠️  Containers not found — creating via compose first..."
    cd ~/librechat && podman-compose --in-pod true up -d \
        || { echo "❌ compose failed."; 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 is up."
        break
    fi
    [ "$i" -eq 10 ] && { echo "❌ API down — last 30 log lines:"; podman logs --tail 30 librechat-app; exit 1; }
    sleep 5
done
 
echo "=== $(date) done ==="

Autostart setup (one-time, already done):

Log file: ​/var/log/librechat-boot.log — ​tail -f /var/log/librechat-boot.log

7. Command Quick Reference

Action Command
Start stack (manual) podman start librechat-app librechat-db librechat-admin
Stop stack podman stop librechat-app librechat-db librechat-admin
Restart containers after changing yaml/env cd ~/librechat && podman-compose –in-pod true down && podman-compose –in-pod true up -d
Update LibreChat image (keeps all data) cd ~/librechat && podman-compose –in-pod true down && podman pull ghcr.io/danny-avila/librechat:latest && podman-compose –in-pod true up -d
View app logs podman logs –tail 100 librechat-app
View mongo logs podman logs –tail 50 librechat-db
View panel logs podman logs –tail 50 librechat-admin
View boot log tail -f /var/log/librechat-boot.log
Pod status podman pod ps
Remove stack, KEEP data cd ~/librechat && podman-compose –in-pod true down
Nuke everything including data above + podman volume rm librechat-db-data librechat-images librechat-uploads librechat-logs
List all users + roles podman exec librechat-db mongosh –quiet –eval 'db.getSiblingDB(“LibreChat”).users.find({}, {email:1, roles:1}).toArray()'
Check LM Studio live models curl -s http://localhost:1234/v1/models

Notes:

8. Troubleshooting Log

8a. Sign-in 500 "secretOrPrivateKey must have a value"

Cause: this image build signs refresh tokens with ​process.env.JWT_REFRESH_SECRET, not REFRESH_TOKEN_SECRET (confirmed at node_modules/@librechat/data-schemas/dist/index.mjs:5989). Registration worked because no token is issued at signup. Fix: JWT_REFRESH_SECRET=<value> in .env + recreate. ✅ Applied.

8b. "Please select an image" prompt hangs scripts

Cause: bare image names trigger podman's interactive registry picker; without a TTY it blocks forever. Fix: fully-qualified names in compose.yaml (docker.io/library/mongo:latest, ghcr.io/danny-avila/librechat:latest). ✅ Applied.

8c. code-interpreter image 403 Forbidden

Cause: ghcr.io/danny-avila/code-interpreter:latest no longer exists in the registry; the official compose no longer ships it either [1]. Fix: service dropped — not needed for chat + ComfyUI MCP. ✅ Applied.

8d. Logo too small on login page

Cause: built-in CSS sizes logo.svg fixed; no interface config key exists for it. Fix: patched index.html → custom.css → img[src*=“logo.svg”] override, 140px + centered. ✅ Verified in browser.

8e. podman-compose --pod not recognized

Cause: the dnf package (v1.6.0) is containers/podman-compose v1.x — different flag than the pipx build. Fix: use ​–in-pod true before the subcommand: podman-compose –in-pod true up -d. ✅ Applied.

8f. "agent_id is required in request body"

Cause: message sent before the LM Studio endpoint was selected in the model picker — request routed to the agents endpoint. Fix: new conversation, select model explicitly first. ✅ Resolved.

8g. Admin panel image 403 on ghcr

Cause: ghcr.io/danny-avila/librechat-admin-panel:latest does not exist there; correct registry is registry.librechat.ai/librechat-ai/librechat-admin-panel:latest per the official compose [1]. Fix: corrected image reference. ✅ Container runs, panel serves at :3090.

8h. Logs show "OpenID check failed: 500 .../openid/check"

Cause: known upstream bug — LibreChat issue #14504, fixed in PR #14507. Maintainer confirms it is log noise, NOT the login blocker (panel treats any non-ok response as “SSO unavailable” and falls back to email/password). Action: none — ignore until an image update includes the fix.

8i. Admin panel login: form submits, nothing happens

⚠️ OPEN ITEM. API logs show ​[Login] [Login successful] [info@root3.de] repeated — credentials accepted, auth works; the panel never establishes a browser session. Prime suspect: session cookies flagged secure over plain HTTP (candidate fixes: SESSION_COOKIE_SECURE=false / ADMIN_PANEL_SESSION_COOKIE_SECURE=false in .env) or panel-side session wiring. Secondary check pending: users.find({}, {email:1, roles:1}) to confirm exactly one user holds the ADMIN role (per #14504 thread, only the first registered user gets it). Status: unresolved — next debugging step is the Network tab on :3090/login (failed request + status code) plus librechat-admin logs during an attempt.

9. Status Overview

Component Status Note
Logo (big + centered) ✅ verified in browser custom.css, 140px
Auth: register + sign-in ✅ working JWT_REFRESH_SECRET fix
LM Studio chat ✅ “Hello!” response confirmed Qwen3 27B via fetch:true
ComfyUI MCP server ✅ “running on stdio” in logs comfyui-mcp package
Admin account ✅ info@root3.de (first user = ADMIN) panel is separate URL :3090
Admin panel service ✅ running, serves :3090 login still open (8i)
Autostart (LLM first) ✅ Nobara Login Script /var/log/librechat-boot.log
Data persistence ✅ named volumes survives recreation/updates
Podman Desktop grouping ✅ pod_librechat, 3 containers –in-pod true
— — —
ComfyUI image generation end-to-end ⏳ not yet tested last open functional test