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%
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> |
||
|---|---|---|
| docs | ||
| man | ||
| scripts | ||
| src/llamacppctl | ||
| tests | ||
| .gitignore | ||
| BEDIENUNGSANLEITUNG.md | ||
| build_archive.py | ||
| INSTALL_FROM_ARCHIVE.md | ||
| llama.cpp.config | ||
| llama.cpp.config.example | ||
| pyproject.toml | ||
| README.md | ||
| requirements-dev.txt | ||
| requirements.txt | ||
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-urlgewinnt 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):
- Eingebaute Defaults
[default]-Sektion[model.<profile>]-Sektion (falls--profilegesetzt)- 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-filelesen 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 überContent-Length` als auch beim Streaming.- Der Port wird standardmäßig nur auf
127.0.0.1veröffentlicht — der ungeauthentifizierte OpenAI-Endpoint ist also nicht im LAN erreichbar.--expose/expose = truebindet auf alle Interfaces; dann sollte per--api-key/api_keyein Schlüssel gesetzt werden (Server verlangt ihn, das Tool sendet ihn als Bearer-Token). container_nameist 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.--changeverwendet 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