server-up/CHANGELOG.md
Ramon 8b29553a71
Some checks failed
Deploy server-up (dev) / deploy (push) Failing after 3s
v0.5.00-beta - containerbeheer, eigen IP-adressen, veiliger installeren
- Beheer per container: de stackkaart klapt uit naar de losse containers, met
  start/stop/herstart, logs en live CPU-/geheugengebruik per container. De
  containernaam wordt getoetst aan compose_ps van díé stack, zodat de route
  geen willekeurige container op de host kan raken.
- Stacks met een eigen IP-adres (macvlan/ipvlan): netwerkbeheer onder
  Instellingen → Netwerken, netwerkkeuze in de installatiemodal met voorstel
  voor het eerstvolgende vrije adres, en automatische omzetting van het
  gerenderde compose-bestand (poortmappings eruit, ipv4_address erin). De
  templates in apps/ blijven ongewijzigd.
- Toegekende IP's worden vastgehouden in .serverup.json en getoond op de
  stackkaart, zodat een volgende installatie ze niet opnieuw uitdeelt.
- Vrije poort voorstellen bij installeren: next_free_port() bestond al maar
  werd nergens gebruikt. Bezette poorten worden in de UI gemeld.
- Genereerknop voor velden die op een geheim wijzen (token/password/secret),
  lokaal gegenereerd via crypto.getRandomValues.
- Compose valideren met `docker compose config` vóór het wegschrijven, zowel
  bij de editor als na het renderen bij installatie. Ontbreekt de compose-CLI,
  dan blokkeert dat een installatie niet.
- Uitloggen in de zijbalk; gebruikersbeheer en wachtwoord wijzigen onder
  Instellingen → Beveiliging.
- docs/netwerken.md (incl. de shim-interface die de host nodig heeft om zijn
  eigen macvlan-containers te bereiken) en docs/beveiliging.md toegevoegd.
- CHANGELOG bijgewerkt; testsuite uitgebreid naar 112 tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
2026-07-26 14:51:32 +02:00

342 lines
15 KiB
Markdown

# v0.5.00-beta — Authenticatie, beveiliging en eigen IP-adressen
> **Let op bij het bijwerken.** Server Up heeft nu een login. Open na het
> bijwerken meteen de webinterface en maak een beheerdersaccount aan — zolang
> dat niet gebeurd is, kan iedereen die de pagina bereikt het account claimen.
> De poort wordt voortaan standaard op `127.0.0.1` gebonden; zet `BIND=0.0.0.0`
> in je `.env` als je er van buiten de server bij moet (liefst achter een
> reverse proxy met TLS — zie `docs/beveiliging.md`).
## 🔐 Authenticatie
Tot nu toe was elke `/api/*`-route open. Omdat Server Up de docker-socket als
root gebruikt, betekende dat: wie de poort kon bereiken, had root op de host.
- Lokale accounts met scrypt-gehashte wachtwoorden, sessiecookie
(`HttpOnly`, `SameSite=Strict`) en lockout na vijf mislukte pogingen.
- Optionele SSO via een reverse-proxy-header (Authelia/Authentik/Cloudflare
Access). De header wordt alleen vertrouwd vanaf een geconfigureerd proxy-IP.
- Loginscherm en eerste-account-setup in de interface; gebruikersbeheer en
wachtwoord wijzigen onder Instellingen → Beveiliging.
## 🛡️ Beveiligingsfixes
- **CSRF**: elke mutatie vereist een `X-CSRF-Token`-header. Routes die de
toestand wijzigen accepteren geen `GET` meer — `/api/docker/restart` was
eerder met een `<img>`-tag vanaf een willekeurige website te triggeren.
- **Path traversal**: `/api/store/install` controleerde de instantienaam niet;
`"instance": "../../…"` schreef buiten de library. Alle stack-, instantie- en
repo-namen lopen nu door één `safe_name()`-validatie.
- **Tokenlek**: git-tokens werden teruggegeven door `/api/repos` en
`/api/settings`. Die zijn vervangen door een `has_token`-vlag; opslaan met een
leeg veld wist het bestaande token niet meer.
- **Git-URL's**: alleen `http(s)://`, `ssh://` en `git@host:pad`. Git's
`ext::`-transport voert een shell-commando uit en wordt nu geweigerd.
- **Templates** renderen in een Jinja2-sandbox (server-side template injection).
- **SSH**: host-keys worden geverifieerd (`accept-new` + `/data/known_hosts`);
eerder stond `StrictHostKeyChecking=no`, waarmee elke MITM onzichtbaar was.
- **Modules**: repo's worden niet meer automatisch bij elke start gepulld
(`AUTO_SYNC_ON_BOOT`, standaard uit) en kunnen per repo op een commit worden
vastgezet.
- Productie-WSGI-server (waitress) i.p.v. de Flask-ontwikkelserver, limiet op
request-grootte, `ProxyFix`, en CSP/`X-Frame-Options`/`nosniff`/
`Referrer-Policy`-headers.
- Tailwind, Alpine en htmx worden meegeleverd in plaats van vanaf een CDN
geladen; Google Fonts is eruit. De interface werkt nu ook offline.
- `config.json` en de sleutel staan op 0600.
## 🌐 Stacks met een eigen IP-adres
Nieuw: geef een stack een eigen adres in je LAN in plaats van poorten op de host
(macvlan/ipvlan). Geen poortconflicten meer, apps op hun eigen standaardpoort, en
je kunt per app firewallen.
- Netwerkbeheer onder Instellingen → Netwerken (driver, host-interface, subnet,
gateway, optionele IP-range).
- Bij het installeren kies je "Poorten op de host" of een netwerk; Server Up
stelt het eerstvolgende vrije adres voor en houdt toegekende adressen vast.
- Het gerenderde compose-bestand wordt automatisch omgezet: poortmappings eruit,
netwerk met `ipv4_address` erin. De templates in `apps/` blijven ongewijzigd.
- Uitleg en valkuilen (waaronder de shim-interface die de host nodig heeft om
zijn eigen macvlan-containers te bereiken) staan in `docs/netwerken.md`.
## 🧩 Beheer per container
De stackkaart klapt uit naar de losse containers: per container starten, stoppen,
herstarten, logs bekijken en live CPU-/geheugengebruik.
## 📦 Veiliger installeren
- Poortvelden krijgen een vrij poortnummer voorgesteld — `next_free_port()`
bestond al maar werd nergens gebruikt. Bezette poorten worden gemeld.
- Velden voor tokens en wachtwoorden krijgen een genereerknop.
- Compose wordt gevalideerd (`docker compose config`) vóór het wegschrijven, dus
een typefout in de editor maakt een draaiende stack niet meer onstartbaar.
## 🔧 Overig
- Testsuite met pytest (112 tests), ook als stap in beide deploy-workflows.
- Audit-log gebruikt één gedeelde SQLite-verbinding — elke job lekte eerder een
file descriptor. Joblogs worden afgekapt op 2000 regels.
- Het `VERSION`-bestand is de enige bron voor het versienummer.
- Lichte `/healthz` voor de healthcheck in plaats van `docker info`.
- `fix-config.sh` verwijderd: bevatte een hardgecodeerd intern IP en
overschreef de configuratie van de gebruiker.
---
# v0.4.60 — Tweecijferig patch-nummer
## Versiebeleid vanaf v0.4.60
Het patch-deel (laatste cijfer) gebruikt nu twee cijfers en loopt in tientallen:
`0.4.60`, `0.4.61`, … `0.4.69`, `0.4.70`. Blijft semver-compatibel (het deel
wordt als geheel getal vergeleken, dus `0.4.60` > `0.4.6`).
---
# v0.4.6 — Kaal versienummer op alle builds
## Wijziging in v0.4.6
De deploy-workflows tonen nu overal het kale versienummer uit het `VERSION`-
bestand (of de tagnaam), zonder `-dev`/`-rc.<sha>`-suffix. Eenvoudiger te lezen;
bump bij elke wijziging gewoon `VERSION`.
---
# v0.4.5 — Releases & in-app update-check
## Nieuw in v0.4.5
### 🏷️ Automatische releases bij een tag
Push je een `v*`-tag, dan maakt de nieuwe `release.yml`-workflow automatisch een
Forgejo-**Release** aan met notes uit de bijbehorende `CHANGELOG.md`-sectie plus
een commit-overzicht sinds de vorige tag. Pre-release tags (bv. `v0.8.4-beta1`)
worden als pre-release gemarkeerd. Zo krijg je een Releases-pagina met duidelijke
changelog per versie, vergelijkbaar met GitHub Releases.
### 🔔 In-app "update beschikbaar"
Server Up vergelijkt de draaiende versie met de laatste release via de Forgejo/
GitHub Releases-API (semver-vergelijking, pre-releases optioneel). Is er een
nieuwere versie, dan verschijnt een melding in de topbar en een blok in
Instellingen → Updates met versie, release-notes en een link. Instelbaar via
`UPDATE_API_URL` (of env `SU_UPDATE_API`) en de optie "pre-releases meenemen".
### 🔖 Versiebeleid
Bump bij elke wijziging het centrale `VERSION`-bestand; tags zijn de bron voor
release-versies (`vX.Y.Z`, of `-beta`/`-rc` voor pre-releases).
---
# v0.4.4 — Nette versienummers op alle builds
## Nieuw in v0.4.4
Centraal `VERSION`-bestand (semver) is nu de bron voor het versienummer. De
deploy-workflows lezen het en bouwen:
- tag `v0.4.4``0.4.4` (productie, toont `v0.4.4`)
- push naar `main``0.4.4-rc.<sha>`
- push naar `dev``0.4.4-dev.<sha>`
Zo zie je voortaan het échte versienummer in de topbar i.p.v. alleen de
git-SHA (`vdev-1eab7c07`). Bump bij elke wijziging alleen nog `VERSION` (en voor
de zekerheid de fallback in `app.py`/`index.html` voor lokale runs).
---
# v0.4.3 — Auto-logo's legacy-apps + fix lege Docker Images
## Nieuw / fixes in v0.4.3
### 🖼️ Automatische logo's voor legacy-apps
Legacy-apps (eigen `app.json`/`stack.json`-stacks) krijgen nu automatisch een
logo via de dashboard-icons CDN, afgeleid uit de app-naam (bv. "Nextcloud" →
`nextcloud.png`). Een expliciete logo-URL in de metadata wint; bestaat het
geraden icoon niet, dan valt de UI terug op het emoji-icoon. Geldt voor zowel
de App Store als geïnstalleerde stacks.
### 🐛 Fix: Docker Images-pagina was leeg
De afbeeldingenlijst gebruikte `:key="img.id"`, maar meerdere tags kunnen
dezelfde image-ID delen → dubbele Alpine-keys waardoor de tabel niet rendert
(en de "geen images"-melding ook niet, want er waren wél images). De `x-for`
gebruikt nu de index als key.
---
# v0.4.2 — App-logo's bij stacks
## Nieuw in v0.4.2
Geïnstalleerde stacks tonen nu het app-logo (of een emoji-icoon als fallback),
zowel op het dashboard als op de Stacks-pagina. Bij installatie wordt het
logo/icoon van de bron-app opgeslagen in `.serverup.json` in de stack-map.
Bestaande installaties krijgen hun logo via een naam-match met de App Store,
dus ze hoeven niet opnieuw geïnstalleerd te worden. De store toonde al logo's
voor boilerplate-apps (via de selfhst/dashboard-icons CDN).
---
# v0.4.1 — Fix: styling werd niet toegepast
## Fix bovenop v0.4.0
De volledige Tailwind-stylesheet faalde stil omdat `.modal` via `@apply` de
eigen CSS-animatieklasse `anim` toepaste. Tailwind's `@apply` accepteert alleen
Tailwind-utilities, geen losse CSS-klassen, waardoor de hele Play-CDN-compilatie
afbrak en de pagina ongestyled (kaal HTML) werd geladen. De animatie staat nu
als gewone CSS-regel (`.anim, .modal { animation: … }`) los van `@apply`.
---
# v0.4.0 — Volledig nieuw UI-ontwerp (Modern SaaS)
## Nieuw in v0.4.0
### 🎨 Compleet herontworpen interface
Volledig nieuw, licht en ruim "Modern SaaS"-ontwerp (Inter-font, indigo accent,
zachte schaduwen, ronde 2xl-kaarten). Nieuwe app-shell: verticale sidebar met
merk-header, gegroepeerde navigatie met actieve indicator en live status-footer;
slanke sticky topbar met dynamische paginatitel en status-chips. Dashboard,
stacks, app store, images-/audittabellen, instellingen, modals, wizard, toasts
en het log-paneel zijn allemaal opnieuw vormgegeven. Inklapbaar menu en grote
touch-targets blijven behouden; volledig mobielvriendelijk.
### 🌗 Thema volgt systeemvoorkeur
Standaard volgt het thema de OS-voorkeur (licht/donker) en reageert live op
wijzigingen. Handmatige override via Auto / Light / Dark in Instellingen.
---
# v0.3.1 — UI-restyle + taalmodule (add-on)
## Nieuw in v0.3.1
### 🎨 Grondige UI-restyle
Grotere, touch-vriendelijke knoppen (min. 44px), ruimere spacing, grotere
typografie en kaarten. Layout gecentreerd met max-breedte voor meer lucht op
grote schermen. Volledig mobielvriendelijk.
### 📐 Inklapbaar menu (ook op desktop)
De hamburger klapt de sidebar nu ook op desktop in/uit; voorkeur wordt onthouden
(`localStorage`), hoofdinhoud en log-paneel schuiven mee. Op mobiel een
tap-to-close overlay.
### 🌐 Taalmodule als add-on
Nieuwe sectie in Instellingen → "Taalmodule": talen toevoegen, bewerken,
verwijderen en ingebouwde talen (NL/EN) dupliceren als startpunt. Editor toont
per sleutel de Engelse referentie met zoekfilter. Backend-endpoints:
`POST/DELETE /api/i18n`, `GET /api/i18n/keys`, `GET /api/i18n/<code>/raw`.
Toegevoegde talen komen als JSON in `translations/` en zijn direct beschikbaar.
---
# v0.3.01 — Boilerplates fixes + git-driven versioning
## Fixes bovenop v0.3.0
### 🔁 Auto-migratie van default-repos voor upgraders
Bestaande installaties (vanaf v0.2.x) hadden de Boilerplates-repo niet zichtbaar
in de App Store omdat hun `config.json` in de `su-data` volume al bestond en de
nieuwe `DEFAULTS["APP_REPOS"]` daardoor werd overschreven.
`core/__init__.py` `load()` doet nu een eenmalige migratie: ontbrekende
default-repos worden bij opstart aangevuld op basis van id, en gemarkeerd in
`MIGRATIONS_DONE: ["v0.3.0_default_repos"]`. Wordt direct gepersisteerd.
Verwijdert een gebruiker de Boilerplates-repo expliciet, dan komt-ie niet
automatisch terug.
### 🧹 YAML-poetsstap na boilerplate-render
Bij stacks waar de meeste optionele groepen uit staan (Authentik, Nextcloud,
etc.) liet de Jinja-render verlaten mapping-sleutels achter (`volumes:`,
`networks:`, etc. zonder kinderen). Docker-compose faalt daarop met *"block
sequence entries are not allowed in this context"*.
`core/boilerplates.py` `_tidy()` heeft nu een `_drop_empty_mappings()` substep
die in meerdere passes mapping-sleutels verwijdert die alleen worden gevolgd
door whitespace/commentaar of een sibling op gelijke/lagere indent. Werkt in
cascade.
### 🏷️ Versie komt nu uit git
`Dockerfile` accepteert `ARG SU_VERSION=dev` en bakt die in `ENV SU_VERSION` +
OCI image-label. Met `docker build --build-arg SU_VERSION=$(git describe ...)`
weet het image zijn eigen versie. De Server Up UI toont automatisch de juiste
waarde, ongeacht wat de productie-compose meegeeft.
Forgejo Actions kan een tag-push automatisch verwerken — zie
`server-up-deploy/README.md`.
## Migratie vanaf v0.3.0
```bash
docker compose build --no-cache
docker compose up -d
```
---
# v0.3.0 — UI rebuild + Boilerplates support
## Hoogtepunten
### 🎨 Nieuwe UI (Tailwind + Alpine + HTMX)
- `templates/index.html` is volledig herschreven. De handgeschreven CSS
(`--bg/--s1/...` variabelen, ad-hoc grid-classes) is vervangen door
Tailwind utility-classes met een gematchte donker/licht-palette.
- Statebeheer via Alpine.js: één `app()` component bovenop het hele document,
geen `$=document.getElementById`-spaghetti meer.
- HTMX is geladen voor toekomstige server-rendered partials. Het bestaande
fetch-RPC patroon blijft werken; HTMX kan progressief worden ingezet.
- Modals, toasts, terminal-overlay en first-run wizard zitten allemaal in
één Alpine-state — geen losse globale variabelen meer.
- Mobiele sidebar gedraagt zich nu correct (slide-in i.p.v. layout-flip).
### 🧩 ChristianLempa Boilerplates ondersteund
Server Up herkent nu twee stack-formaten naast elkaar:
| Formaat | Detectie | Bron |
|---|---|---|
| **Compose** (origineel) | `compose.yml` / `docker-compose.yml` (+ optioneel `stack.json`) | bes-r/server-up |
| **Boilerplate** (nieuw) | `template.json` + `files/` | ChristianLempa/boilerplates-library |
Nieuw bestand `app/core/boilerplates.py`:
- `is_boilerplate(d)` — detectie
- `metadata(d)` — converteert `template.json["metadata"]` (incl. selfhst-icons) naar Server-Up formaat
- `fields(d)` — flattened variable-schema voor de install-modal
- `render_to_dir(src, dest, values)` — rendert `files/*.yaml` met de Jinja-achtige
`<< var >>` + `<%- if expr %>` syntax die de boilerplates gebruiken (Jinja2 met
custom delimiters). Niet-tekst bestanden worden verbatim gekopieerd.
`app/core/git.py``_scan_compose_dirs` herkent beide formaten en zet
`format: "boilerplate"` in de stack-entry zodat de UI er een badge bij kan tonen.
`app/app.py`:
- `_find_stack_src` accepteert ook boilerplate-mappen.
- `POST /api/store/preview` retourneert voor boilerplates het variabelen-schema
(`fields`) plus een gerenderde preview met defaults.
- `POST /api/store/install` met body `{values: {...}}` rendert de templates
voor je voordat de stack gestart wordt.
### ⚙️ Default-repos
Een nieuwe Server Up komt nu uit de doos met twee app-repositories:
1. `bes-r/server-up` — eigen stacks, submap `apps`
2. `ChristianLempa/boilerplates-library` — community templates, submap `compose`
### 📦 Versie / Dockerfile
- `SU_VERSION` = `0.3.0` in `Dockerfile` en `docker-compose.yml`
- `requirements.txt`: Jinja2 expliciet toegevoegd (was al een Flask-dep)
## Migratie vanaf v0.2.29
- Build opnieuw: `docker compose up -d --build --no-cache`
- Bestaande stacks blijven werken (legacy formaat is intact).
- De Boilerplates-repo wordt automatisch toegevoegd voor verse installs.
Bestaande gebruikers kunnen de repo handmatig toevoegen via
Instellingen → Git Repositories met submap `compose`.
## Bekende beperkingen
- Boilerplate-templates met onbekende custom-filters of complexe Ansible-style
conditionals kunnen falen — de fout verschijnt in het terminal-paneel.
- `volumes:` blokken die conditioneel zijn (`<%- if volume_mode == 'local' %>`)
werken; complexere render-logica (loops over services) is nog niet getest.
- HTMX is geladen maar de meeste interacties draaien nog op fetch-RPC. Verdere
migratie naar server-rendered partials kan stapsgewijs in volgende releases.