Initial import: bare-metal stacks, Server UI, GPU fan, tutorials.
Infrastructure configs for GMKtec K11 (Docker, vLLM, LocalAI, ComfyUI, control-plane, gpu-fan agent, Server UI with CLI/file explorer/GPU fan curve). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,451 @@
|
||||
# Server UI — architektura uniwersalnego panelu (research DevOps)
|
||||
|
||||
**Data:** 2026-07-04
|
||||
**Host:** gmktec-k11, Ubuntu 26.04, RTX 3090 Ti
|
||||
**Kontekst:** Czy UI gpu-fan można przenieść do Server UI w Dockerze, skoro daemon NVML musi zostać na hoście (root)? Jak zbudować panel w stylu appliance (Proxmox / TrueNAS) na Ubuntu?
|
||||
|
||||
**Powiązane:**
|
||||
- [`stacks/server-ui/`](../stacks/server-ui/)
|
||||
- [`stacks/gpu-fan/coding-agent/DOCKER-VS-HOST-REPORT.md`](../stacks/gpu-fan/coding-agent/DOCKER-VS-HOST-REPORT.md)
|
||||
- [`DOCKER-UI-DEPLOYMENT.md`](DOCKER-UI-DEPLOYMENT.md)
|
||||
- [`ADR-001-host-agent-control-plane.md`](ADR-001-host-agent-control-plane.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. Executive summary
|
||||
|
||||
**Werdykt:** Przeniesienie **UI** gpu-fan do Server UI przy **daemonie NVML na hoście** to **właściwy, branżowo spójny kierunek** (wzorzec *control plane UI + host agent*). **Nie** pakować sterowania wentylatorami do kontenera Docker.
|
||||
|
||||
**Rekomendowana strategia:** **C** — rozdziel gpu-fan na agent localhost (`127.0.0.1:18090`) + zintegrowany panel w Server UI + dockerizacja Server UI z `docker.sock` i proxy do agenta.
|
||||
|
||||
**Stan dziś:** Oba panele (gpu-fan :8090, server-ui :8091) działają jako **systemd na hoście**, nie w Dockerze. Cel „wszystkie UI serwerowe w Dockerze” wymaga najpierw dockerizacji server-ui, potem integracji gpu-fan jako host agent.
|
||||
|
||||
---
|
||||
|
||||
## 2. Pytanie biznesowe
|
||||
|
||||
> gpu-fan musi działać na hoście (root, NVML). Czy UI gpu-fan może działać w kontenerze Docker razem z server-ui, żeby wszystkie UI serwerowe zarządzały rootem z jednego miejsca?
|
||||
|
||||
**Odpowiedź skrócona:**
|
||||
|
||||
| Warstwa | Gdzie | Dlaczego |
|
||||
|---------|-------|----------|
|
||||
| Pętla NVML + zapis wentylatorów | **Host, systemd, root** | Jedyny wspierany i bezpieczny model ([gpu-fan report](../stacks/gpu-fan/coding-agent/DOCKER-VS-HOST-REPORT.md)) |
|
||||
| API agenta (status, krzywa, tryb) | **Host, localhost only** | Most dla UI bez publicznego NVML |
|
||||
| Web UI (dashboard, wykres, przyciski) | **Server UI (docelowo Docker)** | Jedna przeglądarka, jeden port, jeden API key |
|
||||
| Start/stop stacków Docker | **Server UI + docker.sock** | Wzorzec Portainer/Dockge |
|
||||
|
||||
„UI w Dockerze zarządza rootem” = **proxy HTTP do host agenta**, nie uruchomienie NVML write w kontenerze.
|
||||
|
||||
---
|
||||
|
||||
## 3. Stan obecny (as-is)
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
browser1["Przeglądarka"]
|
||||
browser2["Przeglądarka"]
|
||||
gpuFan["gpu-fan.service root :8090"]
|
||||
serverUI["server-ui systemd :8091"]
|
||||
dockerStacks["Docker stacks"]
|
||||
gpu["GPU NVML"]
|
||||
|
||||
browser1 --> gpuFan
|
||||
browser2 --> serverUI
|
||||
gpuFan --> gpu
|
||||
serverUI -->|"docker compose CLI"| dockerStacks
|
||||
serverUI -.->|"link :8090"| gpuFan
|
||||
```
|
||||
|
||||
| Komponent | Runtime | Port | Uprawnienia | Pliki kluczowe |
|
||||
|-----------|---------|------|-------------|----------------|
|
||||
| gpu-fan | systemd, `User=root` | 8090 | NVML write + FastAPI + static UI w **jednym** procesie | `stacks/gpu-fan/app.py`, `fan_controller.py` |
|
||||
| server-ui | systemd | 8091 | `docker compose` subprocess, `nvidia-smi` read-only | `stacks/server-ui/app.py`, `compose_runner.py` |
|
||||
| comfyui / localai / vllm | Docker | 8188 / 8070 / 8000 | GPU compute | `stacks/*/compose.yaml` |
|
||||
| npmplus | Docker, `network_mode: host` | 80, 443, 81 | reverse proxy | `stacks/npmplus/compose.yaml` |
|
||||
|
||||
### Problemy architektoniczne
|
||||
|
||||
1. **Dwa panele** — porty 8090 i 8091, osobne API key, rozproszony UX.
|
||||
2. **Coupling UI+daemon w gpu-fan** — `app.py` uruchamia wątek NVML i uvicorn w jednym procesie; static HTML woła `/api/*` na tym samym origin.
|
||||
3. **Server-ui nie jest w Dockerze** — mimo nazwy „Docker UI” to FastAPI na hoście (`/opt/server-ui`, `server-ui.service`).
|
||||
4. **Brak jednego entry pointu** — NPMPlus domyślnie nie proxyuje 8090/8091; użytkownik musi znać wiele URL.
|
||||
5. **„Zarządzanie rootem”** — server-ui nie może bezpośrednio pisać do NVML; potrzebuje host agent API.
|
||||
|
||||
### Wymuszenie root w gpu-fan
|
||||
|
||||
```python
|
||||
# stacks/gpu-fan/app.py (linie 161–164)
|
||||
if os.geteuid() != 0 and not DRY_RUN:
|
||||
log.error("GPU fan control requires root (NVML write access). Run with sudo.")
|
||||
sys.exit(1)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Analiza coupling gpu-fan (UI + daemon)
|
||||
|
||||
### Obecna struktura procesu
|
||||
|
||||
```
|
||||
gpu-fan.service (root)
|
||||
└── python app.py
|
||||
├── FanController.run_loop() # wątek daemon — co 2s NVML
|
||||
└── uvicorn :8090
|
||||
├── GET / → static/index.html (~750 linii JS)
|
||||
├── GET /api/status
|
||||
├── GET/PUT /api/curve
|
||||
├── POST /api/mode
|
||||
└── POST /api/reload
|
||||
```
|
||||
|
||||
Frontend (`static/index.html`) używa **względnych** ścieżek (`fetch('/api/status')`) — działa tylko gdy UI i API są na tym samym hoście:porcie.
|
||||
|
||||
### Co można rozdzielić bez ryzyka
|
||||
|
||||
| Element | Zostaje na hoście | Może do Server UI |
|
||||
|---------|-------------------|-------------------|
|
||||
| `fan_controller.py` pętla NVML | **Tak** | Nie |
|
||||
| FastAPI endpoints `/api/*` | **Tak** (localhost) | Proxy z server-ui |
|
||||
| `static/index.html` | Nie | **Tak** |
|
||||
| Graceful shutdown → auto fan | **Tak** (SIGTERM w systemd) | Nie |
|
||||
|
||||
### Docelowy podział (agent)
|
||||
|
||||
```
|
||||
gpu-fan-daemon.service (root)
|
||||
└── python fan_daemon.py # lub app.py --api-only
|
||||
├── FanController.run_loop()
|
||||
└── uvicorn 127.0.0.1:18090
|
||||
└── /api/* only (bez static/)
|
||||
|
||||
server-ui (Docker lub systemd)
|
||||
└── static + proxy /api/gpu-fan/* → http://host.docker.internal:18090/api/*
|
||||
```
|
||||
|
||||
**Krytyczne:** Pętla NVML musi działać **niezależnie** od UI — pad panelu nie może zatrzymać chłodzenia.
|
||||
|
||||
---
|
||||
|
||||
## 5. Porównanie branżowe
|
||||
|
||||
### Proxmox VE (Debian appliance)
|
||||
|
||||
| Aspekt | Implementacja | Lekcja |
|
||||
|--------|---------------|--------|
|
||||
| Web UI | `pveproxy` na hoście | UI oddzielone od workloadów, ale **nie** w „zwykłym” kontenerze aplikacyjnym |
|
||||
| Operacje VM/storage | `pvedaemon`, QEMU, LVM na hoście | Privileged zawsze na host kernel |
|
||||
| Model | Single-node hypervisor | Jeden panel, wiele usług backendowych na hoście |
|
||||
|
||||
Proxmox **nie** pakuje hypervisora do Docker — control plane jest częścią OS.
|
||||
|
||||
### TrueNAS
|
||||
|
||||
| Wariant | UI | Storage / hardware |
|
||||
|---------|-----|------------------|
|
||||
| CORE | nginx + middleware na hoście | ZFS w kernelu |
|
||||
| SCALE | UI w middleware (K8s) | Dane nadal przy host storage stack |
|
||||
|
||||
Lekcja: nawet przy „nowoczesnym” SCALE ciężkie operacje zostają przy hoście.
|
||||
|
||||
### Cockpit (Ubuntu)
|
||||
|
||||
- `cockpit.socket` + moduły na hoście
|
||||
- Dostęp do `systemd`, sieci, storage przez D-Bus / polkit
|
||||
- Oficjalny wzorzec Canonical dla headless Ubuntu
|
||||
|
||||
Alternatywa: zamiast własnego server-ui — Cockpit + plugin. Minus: brak whitelist stacków AI, polityki GPU, custom NVML fan.
|
||||
|
||||
### Portainer / Dockge (homelab Docker)
|
||||
|
||||
| Element | Wzorzec |
|
||||
|---------|---------|
|
||||
| UI | Kontener |
|
||||
| Docker API | Mount `/var/run/docker.sock` |
|
||||
| Host hardware (fan, disk, systemd) | **Poza scope** — nie sterują NVML |
|
||||
|
||||
To jest **najbliższy analog** do waszej wizji dla warstwy Docker; gpu-fan wymaga **dodatkowego** host agent (jak brakujący moduł Portainera).
|
||||
|
||||
### Macierz porównawcza
|
||||
|
||||
| Produkt | UI w kontenerze? | Host privileged ops | Pasuje do gmktec-k11? |
|
||||
|---------|------------------|----------------------|------------------------|
|
||||
| Proxmox | Nie (host) | Tak | Wzorzec appliance, za ciężki |
|
||||
| TrueNAS | Częściowo | Tak | Storage-first, nie AI |
|
||||
| Cockpit | Nie | Tak | Generyczny, słaba integracja AI stacks |
|
||||
| Portainer | Tak | Tylko docker.sock | Brak gpu-fan |
|
||||
| **Server UI (propozycja)** | **Tak (docelowo)** | **Via host agent** | **Dopasowany** |
|
||||
|
||||
---
|
||||
|
||||
## 6. Macierz strategii (A–E)
|
||||
|
||||
### A — Status quo (dwa panele, host systemd)
|
||||
|
||||
- **Plus:** Działa dziś, zero refactoru
|
||||
- **Minus:** 8090 + 8091, dwa klucze, rozproszony UX
|
||||
- **Verdict:** Utrzymanie krótkoterminowe
|
||||
|
||||
### B — Split gpu-fan + UI w server-ui, oba systemd na hoście
|
||||
|
||||
- **Plus:** Jeden port 8091, mniejszy refactor niż Docker
|
||||
- **Minus:** Server-ui nadal nie w kontenerze
|
||||
- **Verdict:** **Dobry krok pośredni** (Faza 1–2 bez Fazy 3)
|
||||
|
||||
### C — Split gpu-fan daemon + server-ui w Dockerze (REKOMENDOWANE)
|
||||
|
||||
- **Plus:** Portainer pattern; jeden panel; agent tylko localhost; :8090 znika z LAN
|
||||
- **Minus:** Dockerfile, mounty, `host.docker.internal` na Linux
|
||||
- **Verdict:** **Strategia docelowa**
|
||||
|
||||
### D — Cockpit zamiast server-ui
|
||||
|
||||
- **Plus:** Dojrzały ekosystem Ubuntu
|
||||
- **Minus:** Custom plugin NVML, brak polityki GPU / whitelist compose
|
||||
- **Verdict:** Tylko przy rezygnacji z własnego UI
|
||||
|
||||
### E — gpu-fan NVML w privileged kontenerze
|
||||
|
||||
- **Plus:** Literalnie „wszystko w Dockerze”
|
||||
- **Minus:** Kruche, `Insufficient Permissions` na GeForce, ryzyko manual fan po crash
|
||||
- **Verdict:** **Odrzuć** — patrz [`gpu-fan/docs/05-DLACZEGO-NIE-DOCKER.md`](../stacks/gpu-fan/docs/05-DLACZEGO-NIE-DOCKER.md)
|
||||
|
||||
**Wybór:** **C**, z opcjonalnym **B** jako pierwsze PR (integracja UI przed dockerizacją).
|
||||
|
||||
---
|
||||
|
||||
## 7. Architektura docelowa (to-be)
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
browser["Przeglądarka"]
|
||||
npm["NPMPlus :443 opcjonalnie"]
|
||||
subgraph dockerPlane [Docker control plane]
|
||||
serverUI["server-ui container :8091"]
|
||||
end
|
||||
subgraph hostAgents [Host systemd root]
|
||||
gpuAgent["gpu-fan-daemon 127.0.0.1:18090"]
|
||||
futureAgent["host-agent przyszłość"]
|
||||
end
|
||||
subgraph workloads [Docker workloads]
|
||||
comfyui["comfyui"]
|
||||
localai["localai"]
|
||||
npmplus["npmplus host network"]
|
||||
end
|
||||
gpu["RTX 3090 Ti"]
|
||||
|
||||
browser --> npm
|
||||
npm --> serverUI
|
||||
browser --> serverUI
|
||||
serverUI -->|"docker.sock"| workloads
|
||||
serverUI -->|"proxy /api/gpu-fan"| gpuAgent
|
||||
serverUI -.->|"future /api/host"| futureAgent
|
||||
gpuAgent --> gpu
|
||||
```
|
||||
|
||||
### Warstwy odpowiedzialności
|
||||
|
||||
| Warstwa | Odpowiedzialność | Technologia |
|
||||
|---------|------------------|-------------|
|
||||
| **Presentation** | Jeden dashboard, auth, nawigacja | server-ui |
|
||||
| **Orchestration** | start/stop compose, logi, polityka GPU | server-ui + `docker.sock` |
|
||||
| **Host agents** | NVML fan; przyszłe: systemd, `/data` health | systemd, API localhost |
|
||||
| **Workloads** | AI inference / image gen | istniejące stacki compose |
|
||||
|
||||
### Co NIE wchodzi do Server UI (scope)
|
||||
|
||||
- Pełne osadzenie ComfyUI / LocalAI SPA w iframe — opcjonalne; dziś wystarczą linki `:8188`, `:8070`
|
||||
- Zastąpienie NPMPlus — osobny stack reverse proxy
|
||||
- Pełny hypervisor (VM, ZFS) — poza zakresem ubuntu-bare-metal
|
||||
|
||||
---
|
||||
|
||||
## 8. Plan implementacji (fazy)
|
||||
|
||||
### Faza 1 — Rozdziel gpu-fan (host)
|
||||
|
||||
**Cel:** Agent API bez publicznego UI.
|
||||
|
||||
| Zadanie | Pliki |
|
||||
|---------|-------|
|
||||
| Wydziel tryb API-only lub `fan_daemon.py` | `stacks/gpu-fan/app.py` lub nowy moduł |
|
||||
| Env: `GPU_FAN_API_HOST=127.0.0.1`, `GPU_FAN_API_PORT=18090` | `.env.example`, `/opt/control-plane/.env` |
|
||||
| Usuń serwowanie `static/` z produkcji | `app.py` |
|
||||
| Zaktualizuj `gpu-fan.service` | `gpu-fan.service` |
|
||||
| Deprecate publiczny :8090 w `enable-lan.sh` | `scripts/enable-lan.sh` |
|
||||
| Dokumentacja | `docs/`, `README.md` |
|
||||
|
||||
**Weryfikacja:**
|
||||
```bash
|
||||
curl -s http://127.0.0.1:18090/api/status -H "X-API-Key: $KEY"
|
||||
ss -tlnp | grep 18090 # 127.0.0.1 only
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://192.168.100.90:8090/ # connection refused
|
||||
```
|
||||
|
||||
### Faza 2 — Integracja UI w server-ui
|
||||
|
||||
| Zadanie | Pliki |
|
||||
|---------|-------|
|
||||
| Przenieś UI gpu-fan do zakładki / podstrony | `server-ui/static/gpu-fan.html` lub sekcja w `index.html` |
|
||||
| Zmień `fetch` na `/api/gpu-fan/...` | JS frontend |
|
||||
| Proxy backend | `server-ui/app.py` — `httpx` lub `requests` do agenta |
|
||||
| Jednolity `API_KEY` dla użytkownika | `.env` server-ui; agent akceptuje ten sam secret z localhost |
|
||||
| Usuń link `:8090` | `server-ui/static/index.html` |
|
||||
|
||||
**Weryfikacja:** Panel gpu-fan w `:8091`, brak potrzeby otwierania :8090.
|
||||
|
||||
### Faza 3 — Dockerize server-ui
|
||||
|
||||
| Zadanie | Pliki |
|
||||
|---------|-------|
|
||||
| `Dockerfile` | `stacks/server-ui/Dockerfile` |
|
||||
| `compose.yaml` | mount `docker.sock`, repo, env |
|
||||
| `extra_hosts: host.docker.internal:host-gateway` | compose |
|
||||
| Opcja: systemd wrapper `docker compose up -d` | `server-ui.service` lub nowy unit |
|
||||
| Whitelist w `stacks.yaml` — bez zmian | — |
|
||||
|
||||
**Weryfikacja:**
|
||||
```bash
|
||||
docker compose --profile server-ui up -d
|
||||
curl -s http://127.0.0.1:8091/api/health
|
||||
curl -s http://127.0.0.1:8091/api/stacks
|
||||
```
|
||||
|
||||
### Faza 4 — Jeden punkt wejścia (opcjonalnie)
|
||||
|
||||
- NPMPlus proxy host `panel.<domena>` → `127.0.0.1:8091`
|
||||
- UFW: zamknij 18090, opcjonalnie 8091 poza LAN
|
||||
- Patrz BACKLOG P1 — rozdział 08 firewall
|
||||
|
||||
### Faza 5 — `host-agent` (przyszłość)
|
||||
|
||||
Jeden daemon root agregujący:
|
||||
- gpu-fan (NVML)
|
||||
- `systemctl` status wybranych unitów (`gpu-fan`, `server-ui`)
|
||||
- health mountu `/data`
|
||||
- wersje driver / CUDA
|
||||
|
||||
Server-ui woła `/api/host/*` zamiast wielu portów agentów.
|
||||
|
||||
---
|
||||
|
||||
## 9. API contract — gpu-fan agent (do proxy)
|
||||
|
||||
Agent nasłuchuje na `127.0.0.1:18090`. Server-ui mapuje `/api/gpu-fan/{path}` → `/api/{path}`.
|
||||
|
||||
| Endpoint agenta | Metoda | Opis | Auth |
|
||||
|-----------------|--------|------|------|
|
||||
| `/api/status` | GET | Temperatura, fan speeds, tryb, krzywa | `X-API-Key` |
|
||||
| `/api/curve` | GET | Punkty krzywej | `X-API-Key` |
|
||||
| `/api/curve` | PUT | Zapis krzywej + tryb curve | `X-API-Key` |
|
||||
| `/api/mode` | POST | `{"mode":"auto\|curve\|manual","speed":100}` | `X-API-Key` |
|
||||
| `/api/reload` | POST | Przeładuj `curve.json` | `X-API-Key` |
|
||||
|
||||
**Bezpieczeństwo agenta:**
|
||||
- Bind tylko `127.0.0.1` (nie `0.0.0.0`)
|
||||
- Akceptuj requesty tylko z loopback lub z zaufanego `GPU_FAN_TRUSTED_PROXY` (server-ui IP w docker bridge — opcjonalnie)
|
||||
- Ten sam `API_KEY` co server-ui lub osobny `AGENT_KEY` w env server-ui (nie w repo)
|
||||
|
||||
**Przykład proxy (szkic Python):**
|
||||
```python
|
||||
# server-ui/app.py (szkic — nie zaimplementowano)
|
||||
GPU_FAN_AGENT = os.environ.get("GPU_FAN_AGENT_URL", "http://127.0.0.1:18090")
|
||||
|
||||
@app.api_route("/api/gpu-fan/{path:path}", methods=["GET", "PUT", "POST"])
|
||||
async def proxy_gpu_fan(path: str, request: Request):
|
||||
require_mutation_auth(request) # lub require_auth dla GET też
|
||||
url = f"{GPU_FAN_AGENT}/api/{path}"
|
||||
# forward method, body, X-API-Key header
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Szkic `compose.yaml` — server-ui (bez implementacji)
|
||||
|
||||
```yaml
|
||||
# stacks/server-ui/compose.yaml — PROPOZYCJA, nie wdrożono
|
||||
name: server-ui
|
||||
|
||||
services:
|
||||
server-ui:
|
||||
build: .
|
||||
container_name: server-ui
|
||||
profiles: [server-ui]
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${SERVER_UI_PORT:-8091}:8091"
|
||||
environment:
|
||||
- SERVER_UI_HOST=0.0.0.0
|
||||
- SERVER_UI_PORT=8091
|
||||
- API_KEY=${API_KEY}
|
||||
- REPO_ROOT=/repo
|
||||
- GPU_FAN_AGENT_URL=http://host.docker.internal:18090
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ${REPO_ROOT:-/home/tomasz-syn-grzegorza/cursor/ubuntu-bare-metal}:/repo:ro
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
```
|
||||
|
||||
**Uwagi:**
|
||||
- `docker compose` w kontenerze wymaga CLI w obrazie lub wywołania Docker API bezpośrednio (obecnie `compose_runner.py` używa subprocess — działa z mounted sock + `docker` CLI w image).
|
||||
- Ścieżki `compose_dir` w `stacks.yaml` muszą istnieć w `REPO_ROOT` wewnątrz kontenera (`/repo/stacks/...`).
|
||||
|
||||
---
|
||||
|
||||
## 11. Ryzyka i mitigacje
|
||||
|
||||
| Ryzyko | Prawdopodobieństwo | Mitigacja |
|
||||
|--------|-------------------|-----------|
|
||||
| Pad server-ui = brak edycji krzywej | Średnie | Daemon gpu-fan **niezależny** — ostatnia krzywa dalej działa |
|
||||
| Server-ui w Docker nie widzi ścieżek compose | Wysokie przy złym mount | Mount całego repo; test `REPO_ROOT` w healthcheck |
|
||||
| `host.docker.internal` niedostępny | Niskie na Docker 20.10+ | `extra_hosts: host-gateway` |
|
||||
| Dwa API key — UX | Średnie | Jeden klucz w UI; proxy dokleja secret do agenta |
|
||||
| Regresja graceful shutdown fan | Niskie przy zachowaniu systemd | Nie ruszać `fan_controller.shutdown()`; test po `systemctl stop` |
|
||||
| npmplus + server-ui port conflict | Brak | 8091 vs 80/443/81 |
|
||||
|
||||
---
|
||||
|
||||
## 12. Anti-patterns (czego unikać)
|
||||
|
||||
1. **NVML fan control w kontenerze Docker** — odrzucone w gpu-fan research.
|
||||
2. **Jeden monolityczny proces root z UI na 0.0.0.0** — obecny gpu-fan; do refaktoru.
|
||||
3. **Server-ui bez docker.sock a z pretensją do zarządzania kontenerami** — wymaga sock lub Docker API.
|
||||
4. **Osadzanie ComfyUI w server-ui zamiast linków** — duży scope, CORS, osobne sesje.
|
||||
5. **Budowa „Proxmox w Dockerze”** — over-engineering dla single-node AI homelab.
|
||||
6. **Publiczny port agenta 18090** — tylko localhost.
|
||||
|
||||
---
|
||||
|
||||
## 13. Autentykacja — model docelowy
|
||||
|
||||
| Warstwa | Mechanizm |
|
||||
|---------|-----------|
|
||||
| Użytkownik → server-ui | `X-API-Key` (mutacje + opcjonalnie odczyt gpu-fan) |
|
||||
| server-ui → gpu-fan agent | Ten sam key lub `AGENT_KEY` w env server-ui; request z kontenera przez `host.docker.internal` |
|
||||
| Użytkownik → ComfyUI/LocalAI | Osobne klucze aplikacji (poza server-ui) |
|
||||
| NPMPlus → server-ui | TLS + opcjonalnie basic auth na proxy host |
|
||||
|
||||
Docelowo: **jeden panel, jeden klucz** do operacji serwerowych (start/stop stacków + gpu-fan).
|
||||
|
||||
---
|
||||
|
||||
## 14. Checklist dla kolejnego agenta
|
||||
|
||||
### Research (ten dokument)
|
||||
- [x] Raport SERVER-UI-ARCHITECTURE-RESEARCH.md
|
||||
- [x] ADR-001-host-agent-control-plane.md
|
||||
- [x] Link w BACKLOG.md
|
||||
|
||||
### Implementacja (przyszłe PR)
|
||||
- [ ] Faza 1: gpu-fan API-only na localhost:18090
|
||||
- [ ] Faza 2: proxy + UI w server-ui
|
||||
- [ ] Faza 3: Dockerfile + compose server-ui
|
||||
- [ ] Faza 4: NPMPlus proxy panel
|
||||
- [ ] Faza 5: host-agent (opcjonalnie)
|
||||
|
||||
---
|
||||
|
||||
## 15. Podsumowanie jednym akapitem
|
||||
|
||||
Przeniesienie **samego UI** gpu-fan do Server UI w Dockerze, przy **daemonie NVML na hoście**, to właściwy plan zgodny z Portainer (UI w kontenerze) i Proxmox (privileged na hoście). Najpierw rozdziel proces gpu-fan na agent localhost i panel, potem dockerizuj server-ui z `docker.sock` i proxy do agenta; w dłuższej perspektywie rozważ jeden `host-agent` zamiast wielu portów. **Nie** przenoś NVML do kontenera.
|
||||
Reference in New Issue
Block a user