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.
  • Python 94.4%
  • Shell 5.6%
Find a file
dschlueter 53b6849c27 fix(docker): override image healthcheck to the configured port
The ghcr.io llama.cpp image bakes in a HEALTHCHECK that curls port 8080
(the llama.cpp default). When the server runs on a different --port (here
8000), that check always fails and Docker reports the container as
"unhealthy" even though it serves fine. Override the healthcheck in the
docker run command to target the configured container_port/health_endpoint,
with a 300s start-period so large-context model loads don't flap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 09:53:33 +02:00
docs docs: bring docs/ and build_archive.py up to date 2026-07-06 17:32:46 +02:00
man feat: harden and extend the CLI (security, UX, robustness, tests) 2026-07-06 16:57:47 +02:00
scripts test(smoke): probe a protected endpoint for the api-key check 2026-07-06 17:25:41 +02:00
src/llamacppctl fix(docker): override image healthcheck to the configured port 2026-07-07 09:53:33 +02:00
tests fix(docker): override image healthcheck to the configured port 2026-07-07 09:53:33 +02:00
.gitignore Initial commit: llamacppctl – llama.cpp Docker server control CLI 2026-07-06 16:36:27 +02:00
BEDIENUNGSANLEITUNG.md docs: add BEDIENUNGSANLEITUNG.md and INSTALL_FROM_ARCHIVE.md 2026-07-06 17:48:39 +02:00
build_archive.py docs: add BEDIENUNGSANLEITUNG.md and INSTALL_FROM_ARCHIVE.md 2026-07-06 17:48:39 +02:00
INSTALL_FROM_ARCHIVE.md docs: add BEDIENUNGSANLEITUNG.md and INSTALL_FROM_ARCHIVE.md 2026-07-06 17:48:39 +02:00
llama.cpp.config config: model profiles inherit the standard port/container 2026-07-06 18:47:50 +02:00
llama.cpp.config.example feat: harden and extend the CLI (security, UX, robustness, tests) 2026-07-06 16:57:47 +02:00
pyproject.toml Initial commit: llamacppctl – llama.cpp Docker server control CLI 2026-07-06 16:36:27 +02:00
README.md test: close coverage gaps + opt-in integration smoke 2026-07-06 17:08:10 +02:00
requirements-dev.txt Initial commit: llamacppctl – llama.cpp Docker server control CLI 2026-07-06 16:36:27 +02:00
requirements.txt Initial commit: llamacppctl – llama.cpp Docker server control CLI 2026-07-06 16:36:27 +02:00

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?"

# Chat mit Live-Streaming und großem Antwortbudget (lange Texte)
llamacppctl --chat --config llama.cpp.config --profile qwen35 \
  --stream --max-tokens 8000 -p "Schreibe eine kurze Rede zum Jahreswechsel."

# 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.
  • Der Port wird standardmäßig nur auf 127.0.0.1 veröffentlicht — der ungeauthentifizierte OpenAI-Endpoint ist also nicht im LAN erreichbar. --expose/expose = true bindet auf alle Interfaces; dann sollte per --api-key/api_key ein Schlüssel gesetzt werden (Server verlangt ihn, das Tool sendet ihn als Bearer-Token).
  • 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 und DNS-Pinning), die Konfigurationsauflösung (inkl. ${ENV}-Expansion), die CLI-Validierung, die Action-Orchestrierung (do_start/do_change/do_check/do_chat, Locking, dry-run) sowie Docker-/HTTP-Operationen (mit gemocktem subprocess bzw. requests) ab.

Für einen End-to-End-Test gegen einen echten Docker + llama.cpp-Server (u. a. --api-key-Round-Trip, Streaming, --check-Exit-Codes) gibt es einen opt-in Rauchtest — er startet einen separaten Container und räumt danach auf:

SMOKE_GPU=1 scripts/smoke.sh

Lizenz

MIT