managarten/docs/WINDOWS_GPU_SERVER_SETUP.md
Till JS 4cb1bc1827 fix(mana-voice-bot): move default port 3050 → 3024 + Windows GPU deployment notes
mana-voice-bot's source default was 3050, which collided with mana-sync.
Today the collision is latent (voice-bot isn't deployed anywhere), but
sooner or later someone is going to start it on a host that's already
running mana-sync and the second one will refuse to bind. Moving to
3024 puts it inside the AI/ML port range alongside its dependencies
(stt 3020, tts 3022, image-gen 3023, llm 3025) and away from sync.

Updated:
- app/main.py — PORT default 3050 → 3024
- start.sh, setup.sh — same fix in the example commands
- CLAUDE.md — full rewrite. Old version described "Mac Mini deployment"
  with launchd; the new version explicitly says "not deployed yet" and
  documents the seven concrete steps to deploy on the Windows GPU box
  alongside the other AI services (Scheduled Task, service.pyw, .env,
  firewall rule, cloudflared route, WINDOWS_GPU_SERVER_SETUP.md update).

docs/WINDOWS_GPU_SERVER_SETUP.md:
- Added the missing ManaVideoGen scheduled task to all four
  Start-ScheduledTask snippets — video-gen has been running on the
  Windows GPU but the doc had never picked it up.
- Added a "mana-video-gen (Port 3026)" service section parallel to the
  existing image-gen one, with venv path, repo pointer, model, etc.
- Added a repo-pendants table mapping C:\mana\services\<svc>\ to the
  corresponding services/<svc>/ directory in the repo, plus a note that
  changes should flow repo→Windows, not the other way around.

docs/PORT_SCHEMA.md:
- Reconciled the warning block with the post-cleanup reality: no more
  active or latent port collisions (image-gen ↔ video-gen and
  voice-bot ↔ sync are both resolved). Listed the actual ports per host
  with public URLs. Kept the planned-vs-actual disclaimer for the
  services that still don't match the aspirational ranges (mana-credits
  3061 vs planned 3002, etc).
2026-04-08 13:14:57 +02:00

27 KiB

Windows GPU-Server: Lokale Einrichtung

Diese Anleitung wird am Windows-PC selbst durchgeführt. Ziel: SSH + Grundkonfiguration, damit der Rechner remote steuerbar ist.

Danach kann alles Weitere (Ollama, AI-Services, Cloudflare Tunnel) per SSH erledigt werden.


Checkliste: Nach jedem Neustart

Wichtig: Bis der Server-Modus (Schritt 9) vollständig konfiguriert ist, können nach einem Neustart einige Dinge manuell geprüft/repariert werden müssen.

PowerShell als Administrator ausführen:

# 1. Netzwerkprofil auf "Privat" setzen
#    (Windows setzt es nach Neustart manchmal auf "Öffentlich" zurück,
#     was die Firewall verschärft und SSH/Ping blockt)
Get-NetConnectionProfile | Set-NetConnectionProfile -NetworkCategory Private

# 2. SSH-Dienst prüfen (muss "Running" sein)
Get-Service sshd
# Falls "Stopped": Start-Service sshd

# 3. AI-Services prüfen
python C:\mana\status.py
# Falls Services nicht laufen:
Start-ScheduledTask -TaskName "ManaLLM"
Start-ScheduledTask -TaskName "ManaSTT"
Start-ScheduledTask -TaskName "ManaTTS"
Start-ScheduledTask -TaskName "ManaImageGen"
Start-ScheduledTask -TaskName "ManaVideoGen"

Wenn Schritt 9 (Server-Modus) korrekt konfiguriert ist, sollte der PC:

  • Nie in den Ruhezustand gehen
  • Nach Neustart automatisch einloggen
  • Alle Services automatisch starten (Scheduled Tasks mit AtLogOn)
  • Netzwerkprofil dauerhaft auf "Privat" stehen

Netzwerkprofil dauerhaft auf "Privat" fixieren

Damit das Netzwerk nach Neustart nicht wieder auf "Öffentlich" springt:

# Variante 1: Per Registry (empfohlen)
# Erst die aktuelle Netzwerk-ID herausfinden:
Get-NetConnectionProfile

# Dann in der Registry fixieren (ProfileType: 1=Privat, 0=Öffentlich):
$profiles = Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles"
foreach ($profile in $profiles) {
    Set-ItemProperty -Path $profile.PSPath -Name Category -Value 1
}

Erstinstallation

Schritt 1: Computername setzen

PowerShell als Administrator öffnen (Rechtsklick → Als Administrator ausführen):

Rename-Computer -NewName "mana-server-gpu"

Noch nicht neu starten — erst alle Schritte durchgehen.


Schritt 2: SSH-Server aktivieren

Gleiche Admin-PowerShell:

# SSH-Server installieren
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

# SSH-Server starten
Start-Service sshd

# Automatisch bei jedem Start
Set-Service -Name sshd -StartupType Automatic

# Standard-Shell auf PowerShell setzen (statt cmd)
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force

Schritt 3: Statische IP vergeben

  1. EinstellungenNetzwerk und InternetEthernet
  2. Bei der aktiven Verbindung auf Bearbeiten klicken (bei IP-Zuweisung)
  3. Auf Manuell umstellen, IPv4 aktivieren:
IP-Adresse:      192.168.178.11
Subnetzmaske:    255.255.255.0
Gateway:         192.168.178.1
Bevorzugter DNS: 192.168.178.1
Alternativer DNS: 1.1.1.1

Mac Mini ist auf 192.168.178.131, Gateway ist 192.168.178.1.


Schritt 4: Firewall-Ports öffnen

Gleiche Admin-PowerShell:

# SSH (sollte schon offen sein, sicherheitshalber)
New-NetFirewallRule -DisplayName "SSH" -Direction Inbound -LocalPort 22 -Protocol TCP -Action Allow

# Ollama
New-NetFirewallRule -DisplayName "Ollama" -Direction Inbound -LocalPort 11434 -Protocol TCP -Action Allow

# AI-Services
New-NetFirewallRule -DisplayName "Mana-STT" -Direction Inbound -LocalPort 3020 -Protocol TCP -Action Allow
New-NetFirewallRule -DisplayName "Mana-TTS" -Direction Inbound -LocalPort 3022 -Protocol TCP -Action Allow
New-NetFirewallRule -DisplayName "Mana-Image-Gen" -Direction Inbound -LocalPort 3023 -Protocol TCP -Action Allow
New-NetFirewallRule -DisplayName "Mana-LLM" -Direction Inbound -LocalPort 3025 -Protocol TCP -Action Allow
New-NetFirewallRule -DisplayName "Mana-Video-Gen" -Direction Inbound -LocalPort 3026 -Protocol TCP -Action Allow

Schritt 5: NVIDIA-Treiber prüfen

nvidia-smi

Falls der Befehl nicht gefunden wird oder der Treiber alt ist (< 535.x):

  1. https://www.nvidia.com/Download/index.aspx → neusten Treiber für deine GPU laden
  2. Installieren, neu starten

Falls nvidia-smi funktioniert → Treiberversion und GPU-Name notieren.


Schritt 6: Python 3.11 installieren

winget install Python.Python.3.11

Falls winget nicht verfügbar: https://www.python.org/downloads/ → 3.11.x

Wichtig: Bei der Installation "Add Python to PATH" ankreuzen!

Prüfen:

python --version

Schritt 7: Git installieren

winget install Git.Git

Prüfen (neue PowerShell öffnen):

git --version

Schritt 8: Arbeitsverzeichnis anlegen

mkdir C:\mana
mkdir C:\mana\services
mkdir C:\mana\venvs
mkdir C:\mana\models

Schritt 9: Server-Modus konfigurieren (Always-On)

Windows ist standardmäßig als Desktop-PC konfiguriert und geht in den Ruhezustand — das führt dazu, dass SSH und alle AI-Services nicht mehr erreichbar sind. Für den Server-Betrieb muss das komplett deaktiviert werden.

PowerShell als Administrator:

# ============================================
# 1. Energiesparplan auf "Höchstleistung" setzen
# ============================================
powercfg /setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c

# ============================================
# 2. Ruhezustand komplett deaktivieren
# ============================================
powercfg /hibernate off

# Standby deaktivieren (Netzbetrieb)
powercfg /change standby-timeout-ac 0
# Bildschirm-Timeout (optional: 0 = nie, oder 30 = 30 Min)
powercfg /change monitor-timeout-ac 30
# Festplatten-Timeout deaktivieren
powercfg /change disk-timeout-ac 0

# ============================================
# 3. Netzwerkadapter darf NICHT in Energiesparmodus
# ============================================
# Alle Netzwerkadapter: Energiesparen deaktivieren
Get-NetAdapter -Physical | ForEach-Object {
    $name = $_.Name
    # Disable "Allow the computer to turn off this device to save power"
    $adapter = Get-WmiObject -Class Win32_NetworkAdapter | Where-Object { $_.NetConnectionID -eq $name }
    if ($adapter) {
        $deviceID = $adapter.PNPDeviceID
        $key = "HKLM:\SYSTEM\CurrentControlSet\Enum\$deviceID\Device Parameters\WDF"
        # Setze PnPCapabilities = 24 (disable power management)
        $regPath = "HKLM:\SYSTEM\CurrentControlSet\Enum\$deviceID"
        if (Test-Path "$regPath\Device Parameters") {
            # Alternative: über Geräte-Manager manuell deaktivieren
            Write-Host "Bitte im Geräte-Manager für '$name' Energiesparen manuell deaktivieren"
        }
    }
}

# ============================================
# 4. USB-Energiesparen deaktivieren (für Peripherie)
# ============================================
powercfg /setacvalueindex SCHEME_CURRENT 2a737441-1930-4402-8d77-b2bebba308a3 48e6b7a6-50f5-4782-a5d4-53bb8f07e226 0
powercfg /setactive SCHEME_CURRENT

# ============================================
# 5. Schnellstart deaktivieren (verursacht Probleme mit SSH nach Neustart)
# ============================================
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Power" /v HiberbootEnabled /t REG_DWORD /d 0 /f

# ============================================
# 6. Automatischen Neustart nach Windows Update verhindern
# ============================================
# Aktive Stunden auf Maximum setzen (verhindert Neustarts tagsüber)
reg add "HKLM\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" /v ActiveHoursStart /t REG_DWORD /d 6 /f
reg add "HKLM\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" /v ActiveHoursEnd /t REG_DWORD /d 2 /f

# ============================================
# 7. Auto-Login nach Neustart (für Scheduled Tasks)
# ============================================
# WICHTIG: Scheduled Tasks mit "AtLogOn" brauchen eine aktive Sitzung.
# Nach einem Neustart muss der User automatisch eingeloggt werden.
# Über GUI: netplwiz → Haken bei "Benutzer müssen Benutzernamen und Kennwort eingeben" entfernen
# Oder per Registry (Passwort wird hier im Klartext gespeichert!):
# reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AutoAdminLogon /t REG_SZ /d 1 /f
# reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v DefaultUserName /t REG_SZ /d "tills" /f
# reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v DefaultPassword /t REG_SZ /d "DEIN_PASSWORT" /f

Manuell im Geräte-Manager prüfen

  1. Geräte-Manager öffnen → Netzwerkadapter → Rechtsklick auf den Ethernet-Adapter
  2. EigenschaftenEnergieverwaltung
  3. Haken bei "Computer kann das Gerät ausschalten, um Energie zu sparen" entfernen

Energiesparplan verifizieren

# Aktiven Energiesparplan anzeigen
powercfg /getactivescheme
# Sollte "Höchstleistung" zeigen

# Alle Einstellungen prüfen
powercfg /query

Schritt 10: Neustart

Restart-Computer

Nach dem Neustart sollte der PC automatisch einloggen (falls Auto-Login konfiguriert) und die Energiespareinstellungen aktiv sein.


Schritt 11: SSH-Key einrichten (passwortloser Zugriff)

Auf dem Windows-PC in PowerShell als Administrator ausführen:

# Für Admin-User muss der Key in die systemweite Datei:
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAmtp92RmE6lPhHRg24VSYIvq9ne4+qe61SiR4c+lPWu claude-code@mana" | Out-File -Encoding utf8 -FilePath C:\ProgramData\ssh\administrators_authorized_keys

# Berechtigungen setzen (Windows erfordert das für SSH)
# Vererbung entfernen
icacls C:\ProgramData\ssh\administrators_authorized_keys /inheritance:r

# Berechtigungen setzen (NT AUTHORITY\SYSTEM funktioniert auf allen Sprachen)
icacls C:\ProgramData\ssh\administrators_authorized_keys /grant "NT AUTHORITY\SYSTEM:(R)"

# Admin-Gruppe: Name hängt von der Systemsprache ab, SID ist immer gleich
$adminGroup = (New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")).Translate([System.Security.Principal.NTAccount]).Value
icacls C:\ProgramData\ssh\administrators_authorized_keys /grant "${adminGroup}:(R)"

Warum nicht ~/.ssh/authorized_keys? Windows OpenSSH ignoriert diese Datei für Benutzer in der Administratoren-Gruppe. Stattdessen wird C:\ProgramData\ssh\administrators_authorized_keys gelesen.


Schritt 12: SSH testen

Vom Mac (dev-Rechner) aus testen:

ssh tills@192.168.178.11

Beim ersten Mal Fingerprint bestätigen mit yes.

Falls erfolgreich, sollte eine PowerShell-Sitzung starten.

Zusätzlich testen:

# GPU erreichbar?
ssh tills@192.168.178.11 "nvidia-smi"

# Python da?
ssh tills@192.168.178.11 "python --version"

Ergebnis

Nach diesen Schritten hat der Windows-PC:

  • Fester Computername (mana-server-gpu)
  • SSH-Server (Port 22, Autostart)
  • Statische IP im LAN
  • Firewall-Ports offen für alle AI-Services
  • NVIDIA-Treiber mit CUDA-Support
  • Python 3.11
  • Git
  • Arbeitsverzeichnis C:\mana\
  • Server-Modus: Kein Ruhezustand, kein Standby, Höchstleistung
  • Auto-Login nach Neustart (für Scheduled Tasks)
  • Schnellstart deaktiviert (sauberer SSH-Boot)

Alles Weitere (Ollama, AI-Services, Cloudflare Tunnel) wird dann per SSH gemacht.


AI-Services Einrichtung (per SSH)

Nach der Grundinstallation wurden folgende AI-Services eingerichtet:

Ollama (LLM Inference)

  • Port: 11434
  • Host-Binding: 0.0.0.0 (LAN-Zugriff via OLLAMA_HOST System-Umgebungsvariable)
  • Installierte Modelle:
    • gemma3:4b (3.3 GB) - Schnelles Chat-Modell
    • gemma3:12b (8.1 GB) - Bessere Qualität
    • qwen2.5-coder:14b (9.0 GB) - Code-Generierung
    • nomic-embed-text - Embedding-Modell

Ollama startet automatisch beim Login (System Tray).

mana-llm (Port 3025)

Zentraler LLM-Gateway mit OpenAI-kompatiblem API. Routet Anfragen an Ollama und Cloud-Provider.

  • Verzeichnis: C:\mana\services\mana-llm\
  • venv: C:\mana\venvs\llm\
  • Config: C:\mana\services\mana-llm\.env
  • Log: C:\mana\services\mana-llm\service.log
  • Autostart: Windows Scheduled Task "ManaLLM" (AtLogOn)

mana-stt (Port 3020)

Speech-to-Text mit faster-whisper (CUDA-beschleunigt auf RTX 3090).

  • Verzeichnis: C:\mana\services\mana-stt\
  • venv: C:\mana\venvs\stt\
  • Config: C:\mana\services\mana-stt\.env
  • Log: C:\mana\services\mana-stt\service.log
  • Autostart: Windows Scheduled Task "ManaSTT" (AtLogOn)
  • Backend: faster-whisper mit CTranslate2 (CUDA float16)
  • Default-Modell: large-v3-turbo (~1.6 GB, wird beim ersten Request geladen)

mana-tts (Port 3022)

Text-to-Speech mit mehreren Backends:

  • Verzeichnis: C:\mana\services\mana-tts\
  • venv: C:\mana\venvs\tts\ (PyTorch 2.5.1+cu121)
  • Config: C:\mana\services\mana-tts\.env
  • Log: C:\mana\services\mana-tts\service.log
  • Autostart: Windows Scheduled Task "ManaTTS" (AtLogOn)
  • Backends:
    • Kokoro (82M, CUDA) — Englische Stimmen, ~1s Latenz, 27 Stimmen
    • Edge TTS (Cloud) — Deutsche Stimmen (Katja, Conrad, etc.), ~2s Latenz
    • Piper (CPU/ONNX) — Lokale deutsche Stimmen (Thorsten, Kerstin), schnell
    • F5-TTS (CUDA) — Voice Cloning mit Referenz-Audio

mana-image-gen (Port 3023)

Bildgenerierung mit FLUX.1-schnell (12B Parameter) via HuggingFace diffusers.

  • Verzeichnis: C:\mana\services\mana-image-gen\
  • Repo-Pendant: services/mana-image-gen/service.pyw, app/main.py, app/flux_service.py, app/api_auth.py, app/vram_manager.py
  • venv: C:\mana\venvs\image-gen\ (PyTorch 2.5.1+cu121)
  • Config: C:\mana\services\mana-image-gen\.env (siehe services/mana-image-gen/.env.example)
  • Log: C:\mana\services\mana-image-gen\service.log
  • Autostart: Windows Scheduled Task "ManaImageGen" (AtLogOn)
  • Modell: FLUX.1-schnell (Apache 2.0, 4-bit quantisiert via BitsAndBytes)
  • HuggingFace: Erfordert Login + Lizenzakzeptanz für gated Model

mana-video-gen (Port 3026)

Videogenerierung mit LTX-Video (~2B Parameter) via HuggingFace diffusers + CUDA.

  • Verzeichnis: C:\mana\services\mana-video-gen\
  • Repo-Pendant: services/mana-video-gen/service.pyw, app/main.py, app/ltx_service.py, setup.sh, requirements.txt
  • venv: C:\mana\venvs\video-gen\ (PyTorch + CUDA + diffusers)
  • Config: C:\mana\services\mana-video-gen\.env
  • Log: C:\mana\services\mana-video-gen\service.log
  • Autostart: Windows Scheduled Task "ManaVideoGen" (AtLogOn)
  • Modell: LTX-Video (Lightricks)
  • HuggingFace: HF_TOKEN erforderlich für Model-Download

Repo-Pendants der anderen GPU-Services

Windows-Pfad Repo-Pfad
C:\mana\services\mana-llm\ services/mana-llm/
C:\mana\services\mana-stt\ services/mana-stt/
C:\mana\services\mana-tts\ services/mana-tts/

Jeder Service hat im Repo eine service.pyw Datei — das ist der Runner, den die Scheduled Tasks aufrufen. Änderungen an einem Service sollten primär im Repo gemacht und dann auf die Windows-Box gespiegelt werden, nicht andersrum.

Management-Skripte

# Status aller Services anzeigen
python C:\mana\status.py

# Alle Services starten (falls nicht via Scheduled Task)
python C:\mana\start-all.py

# Alle Services stoppen
python C:\mana\stop-all.py

# Scheduled Tasks manuell starten/stoppen
Start-ScheduledTask -TaskName "ManaLLM"
Start-ScheduledTask -TaskName "ManaSTT"
Start-ScheduledTask -TaskName "ManaTTS"
Start-ScheduledTask -TaskName "ManaImageGen"
Start-ScheduledTask -TaskName "ManaVideoGen"

# Alle Scheduled Tasks auf einmal anzeigen
Get-ScheduledTask -TaskName "Mana*" | Format-Table TaskName, State

Zugriff: Öffentliche URLs (von überall)

Die GPU-Services sind über den Cloudflare Tunnel des Mac Mini öffentlich erreichbar. Auf dem Mac Mini läuft ein TCP-Proxy (~/gpu-proxy.py als LaunchAgent), der den Traffic an den GPU-Server im LAN weiterleitet.

Internet → Cloudflare → Mac Mini (gpu-proxy.py) → GPU Server (LAN)
Service Öffentliche URL
mana-llm https://gpu-llm.mana.how
mana-stt https://gpu-stt.mana.how
mana-tts https://gpu-tts.mana.how
mana-image-gen https://gpu-img.mana.how
mana-video-gen https://gpu-video.mana.how
Ollama https://gpu-ollama.mana.how
# LLM API
curl https://gpu-llm.mana.how/health
curl -X POST https://gpu-llm.mana.how/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"ollama/gemma3:12b","messages":[{"role":"user","content":"Hallo"}]}'

# STT API (WhisperX mit Word-Timestamps + Speaker Diarization)
curl https://gpu-stt.mana.how/health
curl -X POST https://gpu-stt.mana.how/transcribe \
  -F "file=@recording.wav" -F "language=de" -F "align=true" -F "diarize=true"

# TTS API
curl https://gpu-tts.mana.how/health
curl -X POST https://gpu-tts.mana.how/synthesize/auto \
  -H "Content-Type: application/json" \
  -d '{"text":"Hallo Welt","voice":"de_katja"}' --output hello.wav

# Image Generation (FLUX.2 klein 4B)
curl -X POST https://gpu-img.mana.how/generate \
  -H "Content-Type: application/json" \
  -d '{"prompt":"A cat","width":1024,"height":1024}'

# Video Generation (LTX-Video)
curl https://gpu-video.mana.how/health
curl -X POST https://gpu-video.mana.how/generate \
  -H "Content-Type: application/json" \
  -d '{"prompt":"Ocean waves crashing on rocks","width":704,"height":480}'

# Ollama direkt
curl https://gpu-ollama.mana.how/api/tags

Zugriff: LAN (direkt, schneller)

Vom Mac Mini oder anderen Geräten im gleichen Netzwerk:

curl http://192.168.178.11:3025/health   # mana-llm
curl http://192.168.178.11:3020/health   # mana-stt
curl http://192.168.178.11:3022/health   # mana-tts
curl http://192.168.178.11:3023/health   # mana-image-gen
curl http://192.168.178.11:3026/health   # mana-video-gen
curl http://192.168.178.11:11434/api/tags # Ollama

Verzeichnisstruktur

C:\mana\
├── services\
│   ├── mana-llm\            # LLM Gateway Service (Port 3025)
│   │   ├── src\              # Python-Quellcode (FastAPI + Provider Router)
│   │   ├── .env              # Konfiguration
│   │   ├── service.pyw       # Service Runner
│   │   └── service.log       # Log
│   ├── mana-stt\             # Speech-to-Text Service (Port 3020)
│   │   ├── app\              # Python-Quellcode (faster-whisper CUDA)
│   │   ├── .env
│   │   ├── service.pyw
│   │   └── service.log
│   ├── mana-tts\             # Text-to-Speech Service (Port 3022)
│   │   ├── app\              # Python-Quellcode (Kokoro + Edge TTS + Piper)
│   │   ├── .env
│   │   ├── service.pyw
│   │   └── service.log
│   └── mana-image-gen\       # Bildgenerierung (Port 3023)
│       ├── app\              # Python-Quellcode (diffusers + FLUX)
│       ├── output\           # Generierte Bilder (temporär)
│       ├── .env
│       ├── service.pyw
│       └── service.log
├── venvs\
│   ├── llm\                  # Python venv für mana-llm
│   ├── stt\                  # Python venv für mana-stt (faster-whisper)
│   ├── tts\                  # Python venv für mana-tts (PyTorch+CUDA)
│   └── image-gen\            # Python venv für mana-image-gen (PyTorch+CUDA+diffusers)
├── models\                   # (reserviert für lokale Modelle)
├── start-all.py              # Alle Services starten
├── stop-all.py               # Alle Services stoppen
├── status.py                 # Status-Übersicht
├── healthcheck.py            # Health Check + Auto-Restart (alle 5 Min)
├── healthcheck.log           # Health Check Log
├── log-rotate.py             # Log-Rotation (>10MB → .log.1/.2/.3)
├── log-shipper.py            # Logs an Loki auf Mac Mini senden
└── log-shipper-state.json    # Letzte Leseposition pro Log

Health Check & Auto-Restart

Ein Health-Check-Skript prüft alle 5 Minuten ob die Services laufen und startet gefallene neu. Zusätzlich werden Log-Rotation und Log-Shipping (an Loki) ausgeführt.

  • Skript: C:\mana\healthcheck.py
  • Log: C:\mana\healthcheck.log
  • Scheduled Task: ManaHealthCheck (alle 5 Min)
  • Ausführungsreihenfolge: Health Check → Log-Rotation → Log-Shipping
# Manuell ausführen
python C:\mana\healthcheck.py

# Log ansehen
Get-Content C:\mana\healthcheck.log -Tail 20

Log-Rotation

  • Skript: C:\mana\log-rotate.py
  • Trigger: Wird vom Health-Check alle 5 Min aufgerufen
  • Schwelle: Rotiert ab 10 MB
  • Backups: 3 Kopien (service.log.1, .2, .3)

Monitoring & Logs (Loki + Grafana)

GPU-Service-Logs werden alle 5 Minuten an Loki auf dem Mac Mini geschickt und sind über Grafana durchsuchbar.

GPU Server (healthcheck.py → log-shipper.py)
    → HTTP POST → Mac Mini (Loki :3100)
                     → Grafana (grafana.mana.how)

Komponenten:

Komponente Wo Beschreibung
C:\mana\log-shipper.py GPU Server Liest service.log Dateien, pusht neue Zeilen an Loki
C:\mana\log-shipper-state.json GPU Server Merkt sich letzte Leseposition pro Log
Loki (Docker) Mac Mini Log-Aggregator, 30 Tage Retention
VictoriaMetrics Mac Mini Scraped /metrics und /health der GPU-Services alle 15-30s
Grafana Mac Mini Dashboard unter grafana.mana.how

Loki-Queries in Grafana (Explore → Datasource: Loki):

{job="mana-stt"}                    # Alle STT-Logs
{job="mana-llm"} |= "error"        # LLM-Fehler
{host="gpu-server"}                 # Alle GPU-Server-Logs
{job="healthcheck"} |= "DOWN"      # Service-Ausfälle

Prometheus-Metriken (VictoriaMetrics scraped über LAN):

Target Job Port
GPU LLM gpu-llm 3025 (/metrics)
GPU STT gpu-stt 3020 (/health)
GPU TTS gpu-tts 3022 (/health)
GPU Image Gen gpu-image-gen 3023 (/health)
GPU Video Gen gpu-video-gen 3026 (/health)

TypeScript Client (@mana/shared-gpu)

Shared Package im Monorepo (packages/shared-gpu/) für alle GPU-Services:

import { GpuClient } from '@mana/shared-gpu';

// Öffentlich (von überall, mit API-Key)
const gpu = new GpuClient({
  baseUrl: 'https://gpu.mana.how',
  apiKey: process.env.GPU_API_KEY,
});

// Oder LAN (direkt, schneller)
const gpuLan = new GpuClient({
  baseUrl: 'http://192.168.178.11',
  apiKey: process.env.GPU_API_KEY,
});

// Speech-to-Text (mit Word-Timestamps + Speaker Diarization)
const transcript = await gpu.stt.transcribe(audioBuffer, 'recording.wav', {
  language: 'de',
  diarize: true,
  maxSpeakers: 3,
});
// → { text, words: [{ word, start, end, speaker }], speakers: ['SPEAKER_00', ...] }

// Text-to-Speech (Deutsch: Edge TTS, Englisch: Kokoro)
const { audio } = await gpu.tts.synthesize({ text: 'Hallo Welt', voice: 'de_katja' });

// Image Generation (FLUX.2 klein 4B, ~3s @ 1024x1024)
const image = await gpu.image.generate({ prompt: 'A futuristic city', width: 1024, height: 1024 });
const imageUrl = gpu.image.imageUrl(image.image_url);

// Health Check aller Services
const health = await gpu.healthCheck();
// → { stt: true, tts: true, image: true }

API-Authentifizierung

Alle GPU-Services erfordern einen API-Key für Zugriff auf geschützte Endpoints. /health und /docs sind öffentlich (kein Key nötig).

API-Key: In .env.development unter GPU_API_KEY

Verwendung:

# Mit Header
curl -H "X-API-Key: $GPU_API_KEY" https://gpu-llm.mana.how/v1/models

# Oder als Query-Parameter
curl "https://gpu-stt.mana.how/models?api_key=$GPU_API_KEY"

# Health (kein Key nötig)
curl https://gpu-llm.mana.how/health

Konfiguration auf dem GPU-Server:

Service Env-Variable Datei
mana-llm GPU_API_KEY C:\mana\services\mana-llm\.env
mana-stt API_KEYS, INTERNAL_API_KEY C:\mana\services\mana-stt\.env
mana-tts API_KEYS, INTERNAL_API_KEY C:\mana\services\mana-tts\.env
mana-image-gen GPU_API_KEY C:\mana\services\mana-image-gen\.env

Fehlerbehebung

Server nicht erreichbar (kein Ping, kein SSH)

Häufigste Ursache: Ruhezustand/Energiesparen nicht deaktiviert.

  1. Am PC physisch aufwecken (Taste drücken)
  2. Schritt 9 (Server-Modus) erneut durchführen
  3. Prüfen:
# Aktiven Energiesparplan anzeigen
powercfg /getactivescheme
# Muss "Höchstleistung" zeigen

# Ruhezustand-Status prüfen
powercfg /availablesleepstates
# "Ruhezustand" sollte NICHT aufgeführt sein

# Standby-Timeout prüfen (muss 0 sein)
powercfg /query SCHEME_CURRENT SUB_SLEEP STANDBYIDLE

SSH verbindet nicht (PC ist aber an)

# Auf dem Windows-PC prüfen:
Get-Service sshd           # Muss "Running" zeigen
Test-NetConnection -ComputerName localhost -Port 22   # Muss "TcpTestSucceeded: True" zeigen

# SSH-Dienst neu starten
Restart-Service sshd

Services laufen nicht nach Neustart

Die Services nutzen Scheduled Tasks mit AtLogOn — der User muss eingeloggt sein.

# Prüfen ob Tasks registriert sind
Get-ScheduledTask -TaskName "Mana*" | Format-Table TaskName, State

# Manuell starten
Start-ScheduledTask -TaskName "ManaLLM"
Start-ScheduledTask -TaskName "ManaSTT"
Start-ScheduledTask -TaskName "ManaTTS"
Start-ScheduledTask -TaskName "ManaImageGen"
Start-ScheduledTask -TaskName "ManaVideoGen"

# Status prüfen
python C:\mana\status.py

Falls Tasks als "Ready" statt "Running" angezeigt werden:

  • Auto-Login ist nicht konfiguriert → Schritt 9, Punkt 7
  • Oder: manuell am PC einloggen

Service-Logs prüfen

# Letzten 20 Zeilen eines Logs anzeigen
Get-Content C:\mana\services\mana-llm\service.log -Tail 20
Get-Content C:\mana\services\mana-stt\service.log -Tail 20
Get-Content C:\mana\services\mana-tts\service.log -Tail 20
Get-Content C:\mana\services\mana-image-gen\service.log -Tail 20

nvidia-smi zeigt Fehler

GPU VRAM voll

# GPU-Auslastung prüfen
nvidia-smi

# Einzelnen Service stoppen um VRAM freizugeben
python C:\mana\stop-all.py

# Oder gezielt einen Service neu starten
Stop-ScheduledTask -TaskName "ManaImageGen"
Start-ScheduledTask -TaskName "ManaImageGen"

IP-Adresse stimmt nicht

ipconfig
# → Ethernet-Adapter prüfen, IPv4-Adresse muss 192.168.178.11 sein

Port-Konflikte prüfen

# Alle lauschenden Ports anzeigen (deutsch: "ABHÖREN")
netstat -ano | Select-String "ABHOR"

# Welcher Prozess nutzt einen bestimmten Port?
netstat -ano | Select-String "3025"
Get-Process -Id <PID>