Два host-сервиса на firefly (не Docker — systemd):
llama-swap — hot-swap proxy. Один HTTP-port (0.0.0.0:8089), по OpenAI-совместимым запросам поднимает нужную llama-server модель и выгружает остальные.ollama — отдельный server для GGUF-моделей через ollama CLI/API. Listen 127.0.0.1:11434.| Поддомен | URL | Что |
|---|---|---|
llama (VPN) |
https://llama.vpn.4gain.pro | через traefik → firefly:8089 (llama-swap), доступ ТОЛЬКО через AWG mesh |
⚠ Public-домен
llama.4gain.proснят 2026-05-01 — LLM не должен быть доступен из интернета. DNS A-record удалён, traefik-маршрут убран.⚠ Известная дыра, не закрыта: Host-spoofing на public IP firefly с заголовком
Host: llama.vpn.4gain.proсейчас всё ещё проходит через traefik. ipAllowList-middlewarevpn-onlyнеэффективен в Swarm ingress (traefik видит overlay IP 10.0.x.x). См. TODO в /forGain/runbooks/security-todo.
Compose-сервисы forGain (lo-voicebot, etc) ходят на ollama через docker bridge gateway — http://172.27.0.1:11434/v1.
/etc/llama-swap/config.yaml. Текущая конфигурация — 5 моделей в pool default (single-active, exclusive swap, ttl 600с):
| Модель | Файл | Для |
|---|---|---|
qwen3-8b |
Qwen3-8B-Q4_K_M.gguf |
universal default (8B, ~5GB VRAM) |
deepseek-r1-distill-14b |
DeepSeek-R1-Distill-Qwen-14B-Q4_K_M.gguf |
reasoning |
deepseek-coder-v2-lite |
DeepSeek-Coder-V2-Lite-Instruct-Q4_K_M.gguf |
code |
qwen3-coder-30b |
Qwen3-Coder-30B-A3B-Instruct-Q4_K_M.gguf |
code MoE |
qwen3.6-35b |
Qwen3.6-35B-A3B-UD-Q4_K_M.gguf |
reasoning MoE |
Все llama-server'ы используют /home/models/llama.cpp/build/bin/llama-server (vendored сборка) и GGUF-файлы из /home/models/gguf/<model>/.
Как переключаться через API:
curl https://llama.4gain.pro/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"deepseek-r1-distill-14b","messages":[{"role":"user","content":"привет"}]}'
llama-swap выгрузит текущую активную (если другая) и поднимет нужную. TTL 600с — модель остаётся активной 10 минут после последнего запроса.
/usr/local/bin/llama-swap — release v208 от mostlygeek/llama-swap./etc/systemd/system/llama-swap.service — ExecStart=/usr/local/bin/llama-swap --config /etc/llama-swap/config.yaml --listen 0.0.0.0:8089./usr/bin/ollama — установлен через official curl https://ollama.com/install.sh | sh.ollama.service, user ollama, listen 127.0.0.1:11434.ollama pull <name>.Traefik file-route /mnt/swarm/traefik_data/custom/pro-4gain-llama.yml:
llama.vpn.4gain.pro → http://10.19.1.150:8089 (mesh wildcard cert *.vpn.4gain.pro, middleware vpn-only + redirect-to-https)llama.4gain.pro (public) намеренно отсутствуетDNS:
llama.vpn.4gain.pro → 10.9.0.191 (AWG-IP firefly, RFC1918, не маршрутизируется из интернета)llama.4gain.pro — A-запись удаленаMiddleware vpn-only в _middlewares.yml:
vpn-only:
ipAllowList:
sourceRange:
- "10.9.0.0/21" # AWG mesh
- "10.19.1.0/24" # LAN e1
- "127.0.0.1/8"
- "10.0.0.0/8" # ⚠ overly broad, см. security-todo
Ансибл-роль sm2c-cloud-llm.
cd ansible/playbooks
ansible-playbook -c ssh service-llm-bootstrap.yml
Что роль делает:
ollama через official install.sh (idempotent, no-op если установлен).llama-swap v208 из GitHub releases tarball в /usr/local/bin/./etc/llama-swap/config.yaml только если файла нет (не overwrite'ит live-config). При первом запуске берёт snapshot из roles/sm2c-cloud-llm/files/llama-swap-config.yaml.example.Что роль не делает:
llama.cpp из исходников. На firefly уже собрано в /home/models/llama.cpp/./home/models/gguf/<model>/.Toggles:
sm2c_cloud_llm_install_ollama: false — пропустить ollama.sm2c_cloud_llm_install_llama_swap: false — пропустить llama-swap.default с swap: true / exclusive: true.GGUF-модели не бэкапятся — большие, легко повторно скачать. Конфиг /etc/llama-swap/config.yaml лежит в snapshot роли (files/llama-swap-config.yaml.example).
Changelog
llama.4gain.pro (DNS + traefik route удалены), оставлен только VPN-доступ; зафиксирована известная дыра Host-spoof в security-todo (claude/forGain)sm2c-cloud-llm; раскрыта архитектура (5 моделей, llama.cpp, ollama); ссылка на роль (claude/forGain)