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:
tomasz-syn-grzegorza
2026-07-05 12:02:04 +00:00
commit 359afb3a59
153 changed files with 18169 additions and 0 deletions
+173
View File
@@ -0,0 +1,173 @@
# Server UI — edycja portów stacków
**Data:** 2026-07-05
**Host:** gmktec-k11
**Kontekst:** Linki „Otwórz :PORT” w Server UI brały port z `stacks.yaml`, podczas gdy Docker mapował port z osobnego `stacks/<name>/.env`. Wdrożono jeden source of truth w `.env` stacku + edycję w UI.
**Powiązane:**
- [`stacks/server-ui/`](../stacks/server-ui/)
- [`coding-agent/SERVER-UI-ARCHITECTURE-RESEARCH.md`](SERVER-UI-ARCHITECTURE-RESEARCH.md)
- [`coding-agent/CONVENTIONS.md`](CONVENTIONS.md)
---
## 1. Executive summary
Server UI odczytuje i zapisuje port hosta w pliku `stacks/<name>/.env` (np. `LOCALAI_PORT=8070`). Karty stacków mają pole numeryczne i przycisk **Zapisz port**; po zapisie uruchamiany jest `docker compose up -d --force-recreate` gdy stack działa. Nowa usługa wymaga tylko wpisu w `stacks.yaml` z polami `port_env`, `port_default`, `port_editable`.
---
## 2. As-is / to-be
| Aspekt | Przed | Po |
|--------|-------|-----|
| Źródło portu w linku UI | `stacks.yaml``ui_port` (statyczny) | `stacks/<name>/.env``port_env` |
| Edycja portu | ręcznie w `.env` + restart compose | UI + `PATCH /api/stacks/{id}/port` |
| Nowa usługa | hardcode w JS | metadane w `stacks.yaml` |
| NPMPlus | link :81 | read-only (host network) |
```mermaid
flowchart LR
yaml[stacks.yaml port_env metadata]
env[stack .env]
api[Server UI API]
ui[Stack card port input]
compose[docker compose force-recreate]
yaml --> api
env --> api
api --> ui
api -->|PATCH| env
env --> compose
```
---
## 3. Konfiguracja stacków (`stacks.yaml`)
| Stack | `port_env` | `port_default` | `port_editable` |
|-------|------------|----------------|-----------------|
| localai | `LOCALAI_PORT` | 8080 | true |
| comfyui | `COMFYUI_PORT` | 8188 | true |
| vllm | `VLLM_PORT` | 8000 | true |
| npmplus | — | 81 | false |
**Nowa usługa** — dodaj wpis:
```yaml
- id: myservice
name: My Service
compose_dir: myservice
profile: myservice
container: myservice
ui_port: 9000 # fallback gdy brak w .env
port_env: MYSERVICE_PORT
port_default: 9000
port_editable: true
gpu: false
```
W `docker-compose.yml` stacku: `"${MYSERVICE_PORT:-9000}:9000"`.
---
## 4. API
### `GET /api/stacks`
Każdy stack zawiera dodatkowo:
```json
{
"ui_port": 8070,
"port_env": "LOCALAI_PORT",
"port_editable": true,
"port_default": 8080,
"published_port": 8070,
"port_pending_restart": false
}
```
`port_pending_restart`: kontener działa, ale opublikowany port ≠ wartość w `.env`.
### `PATCH /api/stacks/{stack_id}/port`
**Auth:** `X-API-Key` (jak start/stop)
**Body:**
```json
{ "port": 8070, "recreate": true }
```
**Odpowiedź:**
```json
{
"ok": true,
"stack_id": "localai",
"port": 8070,
"port_env": "LOCALAI_PORT",
"requires_restart": false,
"recreated": true,
"running": true
}
```
**Błędy:**
- `400` — stack bez edycji portu (npmplus)
- `409` — port zajęty / poza zakresem 102465535
- `500` — błąd docker compose
**Zarezerwowane porty:** 80, 443, 8090 (gpu-fan), 18090 (gpu-fan agent), `SERVER_UI_PORT` (8091).
---
## 5. Pliki zmienione
| Plik | Zmiana |
|------|--------|
| `stacks/server-ui/stacks.yaml` | `port_env`, `port_default`, `port_editable` |
| `stacks/server-ui/compose_runner.py` | read/write `.env`, walidacja, recreate |
| `stacks/server-ui/app.py` | `PATCH /api/stacks/{id}/port` |
| `stacks/server-ui/static/index.html` | input portu w kartach stacków |
---
## 6. Weryfikacja
```bash
cd ~/cursor/ubuntu-bare-metal/stacks/server-ui
# Lista stacków z portami
curl -s http://127.0.0.1:8091/api/stacks | python3 -m json.tool
# Zmiana portu (wymaga API_KEY z .env)
curl -s -X PATCH http://127.0.0.1:8091/api/stacks/localai/port \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"port":8070,"recreate":true}'
grep LOCALAI_PORT ../localai/.env
```
**UI:** zakładka Stacki → karta LocalAI → pole portu → **Zapisz port** → link „Otwórz” się aktualizuje.
**Prod:** `sudo scripts/install.sh && sudo systemctl restart server-ui`
---
## 7. Uwagi operacyjne
- Po zmianie `LOCALAI_PORT` zaktualizuj **upstream w NPMPlus** ręcznie (proxy host → nowy port).
- `docker compose restart` **nie** zmienia mapowania portów — wymagany recreate (`recreate: true` w API).
- NPMPlus (`network_mode: host`) — port 81 tylko do odczytu w UI.
---
## 8. Checklist wdrożenia
- [x] Metadane portów w `stacks.yaml`
- [x] Backend: odczyt/zapis `.env`, walidacja, recreate
- [x] API `PATCH /port`
- [x] UI: input + Zapisz w kartach
- [x] NPMPlus read-only
- [ ] `install.sh` + restart server-ui na produkcji
- [ ] Test zmiany portu LocalAI na hoście