This is an old revision of the document!
Table of Contents
Local AI Stack - Part 1: Base Setup (LM Studio + Open WebUI + ComfyUI)
Scope: install the three core components on a Nobara system and connect them. Everything runs locally, no cloud access.
Components and their roles:
| Component | Role | Port | Where it runs | ||||
| LM Studio | loads and serves the LLM, provides the lms CLI | 1234 | AppImage on the host | ||||
| Open WebUI | chat interface, user accounts, knowledge base (RAG) | 3000 | Podman container | ||||
| ComfyUI | image generation with Z-Image | 8188 | Python venv on the host | ||||
| Qwen3 27B (GGUF) | the LLM weights, about 16 GB | - | stored in ~/.lmstudio |
Important principle: LM Studio and the model live on the host. Open WebUI only talks to LM Studio over the network (port 1234). That means updating or replacing the LM Studio AppImage never breaks the WebUI connection - only the model files in ~/.lmstudio matter, and those are not part of the AppImage.
1. Prerequisites
| Requirement | Details | Check command | |||
| GPU | NVIDIA card with 16 to 19 GB VRAM (needed for Qwen3 27B) | nvidia-smi | |||
| NVIDIA driver | current driver, working | nvidia-smi shows card, driver and CUDA version | |||
| RAM | 32 GB comfortable, 16 GB minimum | free -h | |||
| Disk space | about 25 GB free for model + container + documents | df -h /home | |||
| Podman | installed, used for Open WebUI | podman –version | |||
| User account | rootai, home directory /home/rootai | whoami | |||
| Ports | 1234, 3000, 8188 must be free | sudo lsof -i :1234 -i :3000 -i :8188 |
If nvidia-smi is not found, install the driver first.
2. Install LM Studio (AppImage)
Why AppImage: it is one self-contained file. Updating later means replacing the file - your models, settings and scripts are not inside it.
Step 2.1 - Download:
Download the latest LM Studio AppImage and store it in /home/rootai/Downloads.
Step 2.2 - Make it executable:
chmod +x /home/rootai/Downloads/lm-studio-*.AppImage
Step 2.3 - Run it (Nobara/Fedora FUSE workaround):
Fedora-based systems do not enable FUSE for normal users by default, so the AppImage may fail with a FUSE or mount error. If that happens:
cd /home/rootai/Downloads ./lm-studio-*.AppImage --appimage-extract ./lm-studio-*/AppRun
This unpacks the AppImage into a folder and starts it via AppRun. It behaves exactly like the normal AppImage.
Step 2.4 - Load the model:
In LM Studio: Models tab, search for Qwen3 27B, download the GGUF variant (about 16 GB). Models are stored in ~/.lmstudio - this directory survives every AppImage update.
Step 2.5 - Link the lms CLI globally:
LM Studio provides the lms command (used by start-ai.sh). Create a stable symlink so scripts do not depend on the exact AppImage filename:
sudo ln -sf /home/rootai/Downloads/lm-studio-*.AppImage /usr/local/bin/lms
Note: after updating LM Studio to a new version (new filename), recreate this symlink - otherwise lms breaks. This is the only update-sensitive part of the whole stack.
Step 2.6 - Verify:
lms ls
Expected: the command runs and lists the model.
3. Start the LM Studio Server and test the API
Step 3.1 - Start the server:
In LM Studio: Developer tab, set port 1234, click Start Server. (The lms load command below also starts the server automatically.)
Step 3.2 - Load the model:
lms load qwen/qwen3.8-27b
Wait until the load finishes (about 16 GB into VRAM, takes a few seconds).
Step 3.3 - Test the OpenAI-compatible API:
curl -s http://127.0.0.1:1234/v1/models
Expected: JSON output that contains qwen3.8-27b. If this works, the LLM side is done.
4. Open WebUI (Podman container)
Step 4.1 - Pull the image:
podman pull ghcr.io/open-webui/open-webui
Step 4.2 - Create and start the container:
podman run -d --name open-webui -p 3000:8080 -v open-webui-data:/app/backend/data --restart unless-stopped ghcr.io/open-webui/open-webui
Explanation of the flags:
* –name open-webui - fixed name, used by start-ai.sh (podman restart open-webui) * -p 3000:8080 - host port 3000 mapped to container port 8080 * -v open-webui-data:/app/backend/data - all settings, users and knowledge base live in this volume and survive container updates * –restart unless-stopped - restart automatically after a reboot
Step 4.3 - Verify it is running:
podman ps | grep open-webui curl -sI http://127.0.0.1:3000 | head -1
Expected: an HTTP 200 or 302 line from curl.
Step 4.4 - Configure in the browser:
Open http://<server-ip>:3000 and log in as admin, then:
# Settings, Connections, add OpenAI API
- Base URL: http://host.docker.internal:1234/v1
- API key: any non-empty value (LM Studio ignores it)
- Test: qwen3.8-27b must appear in the model list
- Why host.docker.internal: from inside the container, localhost points to the container itself, not to the host
# Settings, Models: set nomic-embed-text-v1.5 as the embedding model (needed for RAG, see Part 2)
# Settings, Users: create the user artz
# Disable the built-in Ask User tool: otherwise the model asks follow-up questions instead of answering directly from the documents
5. ComfyUI (Z-Image)
Step 5.1 - Start in the background with logging:
nohup ~/comfyui-env/bin/python ~/comfyui/main.py --listen --port 8188 >> ~/comfyui.log 2>&1 &
Step 5.2 - Verify:
curl -s http://127.0.0.1:8188/system_stats
Expected: JSON with system statistics. For problems:
tail -f ~/comfyui.log
Step 5.3 - Connect in Open WebUI:
Settings, Connections, add ComfyUI:
* URL: http://host.docker.internal:8188 (same reason as above - Open WebUI runs in a container) * Model: Z-Image
6. Auto-start on boot
File: /home/rootai/start-ai.sh (this is the existing script, unchanged)
#!/bin/bash # wait for system services and the LM Studio server to come up sleep 15
# load the Qwen model into LM Studio (also starts the server) lms load qwen/qwen3.8-27b
# give the model a few seconds to fully initialize sleep 10
# restart Open WebUI so it reconnects to the LM Studio API podman restart open-webui
Make it executable:
chmod +x /home/rootai/start-ai.sh
Order matters: LM Studio first, then the model, then Open WebUI.
After an LM Studio update: only step 2.5 (recreate the lms symlink) is needed. The script, the container and the WebUI configuration are untouched.
7. Final smoke test
Run all three checks:
# 1. LM Studio API curl -s http://127.0.0.1:1234/v1/models
# 2. Open WebUI reachable curl -sI http://127.0.0.1:3000 | head -1
# 3. ComfyUI reachable curl -s http://127.0.0.1:8188/system_stats | head -c 100
Then in the browser:
# Open http://<server-ip>:3000, log in as artz # Start a chat with qwen3.8-27b, ask a simple question without a knowledge base # Expected: a normal answer, no citations (citations come with RAG, see Part 2)
8. Troubleshooting
| Symptom | Likely cause | Fix | |||
| AppImage will not start | FUSE not enabled for the user (Fedora default) | use –appimage-extract and AppRun (step 2.3) | |||
| lms: command not found | symlink points to an old AppImage filename | redo step 2.5 with the new path | |||
| WebUI cannot find the model | wrong base URL from the container | use http://host.docker.internal:1234/v1, not localhost | |||
| podman restart fails | wrong container name | check the real name with podman ps -a | |||
| Port already in use | an old process still holds the port | sudo lsof -i :1234 (same for 3000 and 8188), kill the process | |||
| Slow first answer after boot | model still loading | wait for the full load, watch the LM Studio status bar |
Local AI Stack - Part 2: RAG Knowledge Base (Zahnarztabrechnung)
Scope: load the five billing documents into the knowledge base Zahnarztabrechnung, create the model Zahn-Abrechnungs-Assistent, and verify that answers come from the documents with correct sources.
Prerequisite: Part 1 is complete - LM Studio serves qwen3.8-27b on port 1234 and Open WebUI is reachable on port 3000.
1. Set the embedding model (must be first)
RAG works in two steps:
# The document text is split into chunks and converted into vectors (embeddings) by the embedding model. # At chat time, the question is embedded the same way and the most similar chunks are retrieved and shown as citations.
Without an embedding model, step one cannot happen and the knowledge base stays empty.
# Open WebUI, Settings, Models # Embedding model: set nomic-embed-text-v1.5 (built-in, no Ollama or extra LM Studio model needed) # Verify: the model list shows the embedding model as active
Fallback: if German retrieval quality is poor, install bge-m3 via Ollama and switch the embedding model to it.
2. Prepare the PDFs
| # | Document | Source | Note | ||||
| 1 | SGB V (full text) | gesetze-im-internet.de | 577 pages, includes unrelated areas (pharmacy, hospital) - see step 2.1 | ||||
| 2 | KZBV FZ-Kompendium 2025 | KZBV | statutory co-payments (Festzuschüsse) | ||||
| 3 | GOÄ/GOZ | pkv.de | private fee schedules | ||||
| 4 | BEL-Preisliste 2025 | kvzbw.de | billing positions for dental labs | ||||
| 5 | BEB-Preisliste 2024 | itzgmbh.de | image-based (scanned) - OCR required, see step 3 |
Pre-check for every PDF (30 seconds each):
# Open it in a browser or PDF viewer # Try to select and copy some text # If text copies - OK # If the page shows only an image - OCR problem (this is the BEB file)
Step 2.1 - Trim SGB V (optional, recommended):
The full SGB V is 577 pages and pulls in pharmacy and hospital content that can show up as citations for dental questions. If you see such noise in the answer sources, replace the document with a trimmed version containing only Part 3, sections 55 to 66 (the dental-related chapters), and re-index (delete the old document first).
3. Enable OCR for the image-based BEB file
Symptom without OCR: BEB citations are missing or wrong, while all other documents work fine. Reason: the BEB PDF pages are scanned images, so text extraction returns nothing.
Fix:
# Open WebUI, Admin, Settings, Documents # Turn ON the option PDF Extract Images (OCR) # Delete the old BEB entry in the knowledge base (important - otherwise the stale empty index stays) # Upload the BEB PDF again # Wait until the status shows processed
OCR is slower than normal extraction - a larger PDF can take several minutes. That is expected.
4. Create the knowledge base
# Open WebUI, Knowledge, create a new knowledge base # Name: Zahnarztabrechnung # Add documents: upload all five PDFs (BEB after the OCR step) # Wait until every document shows the status processed, no errors # Set permissions: user artz, access Read
Quick test (before the model):
# New chat session, attach the knowledge base Zahnarztabrechnung # Ask: What statutory co-payment applies to a crown? # Expected: an answer with visible source citations from the FZ-Kompendium 2025
5. Create the Zahn-Abrechnungs-Assistent model
# Open WebUI, Settings, Models, create # Name: Zahn-Abrechnungs-Assistent # Base model: qwen3.8-27b (from LM Studio) # Attach the knowledge base Zahnarztabrechnung # System prompt (German, direct style):
Du bist ein Experte fuer die deutsche Zahnarzt- und Zahntechnikerabrechnung (GOA/GOZ, KZBV FZ-Kompendium, BEL und BEB, SGB V).
Antworte direkt auf Basis der bereitgestellten Dokumente. Nenne immer: - die konkrete Positionsnummer - den Preis - die Edition der Preisliste (z. B. BEB 2024, BEL 2025) - das Quelldokument
Stelle keine Rueckfragen. Wenn Informationen fehlen, sage das klar, statt zu raten. Dieses Tool erteilt keine Rechtsberatung.
# Disable the built-in Ask User tool for this model - this is the most common cause of the model asking “which tooth number?” instead of answering
6. End-to-end test
# Browser: http://<server-ip>:3000, log in as artz # Select the model Zahn-Abrechnungs-Assistent # Ask the following questions one by one:
| Test question | Expected answer elements | ||
