llamacppctl/README.md
dschlueter 3158d16f9b Initial commit: llamacppctl – llama.cpp Docker server control CLI
Steuert einen llama.cpp-Server als Docker-Container: --start/--check/--stop/
--change/--chat, INI-Konfiguration (builtin defaults -> [default] ->
[model.<profile>] -> CLI), SSRF-gehärtete Prompt-Eingabe (Datei/HTTPS-URL),
File-Locking für --start/--change und ein OpenAI-kompatibler HTTP-Layer.

Enthält u. a.:
- Env-Var-Expansion in hf_home (hf_home = ${HF_HOME})
- konfigurierbares Chat-Antwortbudget (max_tokens/chat_temperature,
  CLI: --max-tokens/--chat-temp); temperature defer an Server-Default
- DNS-Pinning gegen DNS-Rebinding bei URL-Quellen
- dry-run als nebenwirkungsfreie Vorschau (kein Lock/Removal/Modell-Check)
- 98 Tests (pytest)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 16:36:27 +02:00

5.8 KiB

llamacppctl

Ein einziges, sicherheitsgehärtetes CLI-Werkzeug zum Starten, Prüfen, Stoppen und Wechseln von llama.cpp-Server-Instanzen, die als Docker-Container laufen — inklusive einer SSRF-gehärteten Eingabeschicht für System- und User-Prompts aus Text, Datei oder Remote-URL.

llamacppctl ersetzt eine Sammlung einzelner Shell-Skripte (start-llm-server.sh, status-llm-server.sh, switch-llm.sh, …) durch ein einziges Python-Paket mit konsistenter Konfiguration, Locking und Fehlerbehandlung.

Installation

tar xzf llamacppctl-installable.tar.gz
cd llamacppctl
python3 -m venv .venv
source .venv/bin/activate
pip install .

Danach steht der Befehl llamacppctl innerhalb der aktivierten virtuellen Umgebung zur Verfügung. Für eine systemweite Installation (ohne venv):

pip install --user .

Voraussetzungen auf dem Zielsystem:

  • Python >= 3.10
  • Docker (CLI + laufender Daemon), für --start/--check/--stop/--change`
  • Netzwerkzugriff auf den Container-Host-Port für --chat/--check`

--print-effective-config und --dry-run benötigen keinen laufenden Docker-Daemon für die reine Konfigurationsprüfung; --start/--check/--stop/--change` erfordern einen erreichbaren Docker-Daemon.

Konfiguration

Kopiere llama.cpp.config.example nach llama.cpp.config und passe es an:

cp llama.cpp.config.example llama.cpp.config

Abschnittstypen:

  • [default] — globale Defaults, überschreiben die eingebauten Fallback-Werte
  • [model.<name>] — ein Modell-Profil, ausgewählt über --profile <name>
  • [prompt.<name>] — ein System-Prompt-Profil, ausgewählt über --system-prompt-profile <name> (liefert nur einen Fallback-Systemprompt; ein explizites -s/--system-file/--system-url gewinnt immer)

container_name ist Pflicht und muss für jedes Profil, das parallel laufen soll, eindeutig sein — er ist der einzige Identitätsanker für Docker-Namensgebung, Locking (--start/--change) sowie --stop/--check-Ziel.

hf_home unterstützt Environment-Variablen und ~, z. B. hf_home = ${HF_HOME}.

Das Chat-Antwortbudget ist ebenfalls konfigurierbar (wirkt auf --chat und die Antwort nach --start, nicht auf den Container): max_tokens (Default 2048 — für Reasoning-Modelle / lange Texte hochsetzen, sonst bricht die Antwort mitten im „Denken" ab und content bleibt leer) und chat_temperature (leer = Server-temp gilt). CLI-Overrides: --max-tokens, --chat-temp.

Auflösungsreihenfolge (niedrigste zu höchster Priorität):

  1. Eingebaute Defaults
  2. [default]-Sektion
  3. [model.<profile>]-Sektion (falls --profile gesetzt)
  4. CLI-Overrides (--image, --host-port, …)

Verwendung

# Server starten
llamacppctl --start --config llama.cpp.config --profile qwen35

# Nur den geplanten docker-run-Befehl anzeigen, nichts ausführen
llamacppctl --start --config llama.cpp.config --profile qwen35 --dry-run

# Effektive Konfiguration als JSON ausgeben
llamacppctl --print-effective-config --config llama.cpp.config --profile qwen35 --start

# Status prüfen
llamacppctl --check --config llama.cpp.config --profile qwen35

# Server stoppen und Container entfernen
llamacppctl --stop --config llama.cpp.config --profile qwen35

# Modell wechseln (stop, neu konfigurieren, restart) unter Lock-Schutz
llamacppctl --change --config llama.cpp.config --profile deepseek

# Direkten Chat-Request an einen laufenden Server senden
llamacppctl --chat --config llama.cpp.config --profile qwen35 \
  -s "Du antwortest kurz." -p "Was ist 2+2?"

# System-Prompt aus einer lokalen Datei, User-Prompt als Literal
llamacppctl --start --config llama.cpp.config --profile qwen35 \
  --system-file ./prompts/coding.md -p "Refaktoriere diese Funktion."

# System-Prompt von einer HTTPS-URL (öffentliches, nicht-privates Ziel)
llamacppctl --chat --config llama.cpp.config --profile qwen35 \
  --system-url https://example.com/prompts/system.txt -p "Hallo"

Vollständige Optionsliste: llamacppctl --help oder die Manpage (man/llamacppctl.1, siehe unten).

Sicherheitsmodell (Kurzfassung)

Für Details siehe docs/SECURITY_AND_OPERATIONS.md.

  • Alle Docker-Aufrufe laufen über subprocess.run() mit Argumentlisten — niemals über Shell-Strings, somit keine Shell-Injection-Fläche.
  • --system-file/--prompt-file lesen ausschließlich reguläre Dateien, Größenlimit (--max-input-bytes, Default 1 MiB), UTF-8-Text erzwungen, Symlinks standardmäßig abgelehnt, per --allow-symlinks` freischaltbar.
  • --system-url/--prompt-urlsind standardmäßig HTTPS-only, blockieren IP-Literale, private/loopback/link-local/reserved Adressbereiche sowie die Cloud-Metadata-IP169.254.169.254, verbieten eingebettete Zugangsdaten in der URL, erlauben standardmäßig keine Redirects (jeder Hop wird bei Aktivierung erneut validiert), erzwingen eine Content-Type-Allowlist und ein hartes Größenlimit sowohl über Content-Length` als auch beim Streaming.
  • container_name ist verpflichtend und muss pro parallel betriebenem Profil eindeutig sein, um Docker-Namenskollisionen und ungewollte Container-Übernahmen zu verhindern.
  • --start/--change` nutzen echte Chat-Completions zum Readiness-Check (nicht nur einen offenen Port), um sicherzustellen, dass das Modell tatsächlich geladen und inferenzfähig ist.
  • --change verwendet eine exklusive, nicht-blockierende Dateisperre (/tmp/llamacppctl.<container_name>.lock), um parallele Änderungen am selben Container zu verhindern.

Entwicklung / Tests

pip install -e ".[dev]"
pytest -q

Die Test-Suite deckt die Prompt-Eingabeschicht (Datei- und URL-Quellen inkl. SSRF-Abwehr mit gemockter DNS-Auflösung), die Konfigurationsauflösung, die CLI-Validierung sowie Docker-/HTTP-Operationen (mit gemocktem subprocess bzw. requests) ab.

Lizenz

MIT