# 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//.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//.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//.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 1024–65535 - `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