Het dashboard meldde 13 actieve containers en 17 images terwijl die nergens terug te vinden waren. De tellers komen van `docker info` (de hele daemon), de stacklijst toont alleen mappen in LIBRARY_DIR met een compose-bestand. Alles wat buiten Server Up om gestart is telde dus wel mee maar was onzichtbaar. - Nieuw /api/containers: alle containers op de host, met per container of hij bij een beheerde stack hoort (compose-project of werkmap onder LIBRARY_DIR). - Blok "Overige containers" onder de stacklijst, met start/stop/herstart/logs. - Dashboardteller "actief" vermeldt nu hoeveel daarvan via Server Up loopt. - De eigen container is gemarkeerd en kan niet via dit blok gestopt worden; daarvoor blijft de herstartknop in de instellingen. - Rollen: een viewer ziet de lijst maar mag niets bedienen. Verholpen tijdens het bouwen: containers zonder poorten en zonder compose-labels vielen uit de lijst als ze als laatste regel stonden, doordat strip() de lege velden aan het eind wegnam en de regel daarna te weinig kolommen leek te hebben. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
30 KiB
v0.5.50-beta — Containers die nergens te vinden waren
Het dashboard meldde 13 actieve containers en 17 images, terwijl je die nergens terugzag. Dat kwam doordat de cijfers en de lijst uit twee verschillende bronnen komen:
- de tellers komen van
docker infoen gaan over de hele Docker-daemon - de stacklijst toont alleen mappen in
LIBRARY_DIRmet een compose-bestand
Alles wat je buiten Server Up om had gestart — je Forgejo, de act_runner, containers van vóór je Server Up ging gebruiken — telde dus wel mee maar was onzichtbaar en onbedienbaar. Een beheertool die dingen telt die hij niet toont, is verwarrend.
Wat er nu is
- Overzicht van alle containers op de host. Onder de stacklijst staat een blok "Overige containers" met alles wat niet bij een beheerde stack hoort, inclusief image, poorten en compose-project. Starten, stoppen, herstarten en logs bekijken kan direct.
- De dashboardteller vertelt nu het hele verhaal: onder "actief" staat hoeveel daarvan via Server Up loopt.
- De eigen container is gemarkeerd als "deze app" en kan niet via dit blok gestopt worden — daarvoor is de herstartknop in de instellingen, die dat netjes afhandelt in plaats van zichzelf halverwege een verzoek te stoppen.
- Een viewer ziet de lijst wel maar kan niets bedienen.
Verholpen tijdens het bouwen
Containers zonder poorten én zonder compose-labels vielen weg uit de lijst als
ze toevallig als laatste stonden: strip() haalde de lege velden aan het eind
van de uitvoer weg, waarna die regel te weinig kolommen leek te hebben. Gevonden
door de test die precies zo'n container als laatste zet.
v0.5.43-beta — Van-tot omrekenen naar een CIDR-blok
"Ik wil van 10.0.20.200 tot .254" is een volstrekt redelijke wens, maar bestaat niet als CIDR-notatie: dat zijn 55 adressen, en Docker accepteert alleen uitgelijnde blokken van 2, 4, 8, 16 … adressen.
Onder het IP-range-veld zit nu een van-tot-hulp. Vul de eerste en laatste gewenste adressen in en Server Up rekent uit welke blokken in de buurt komen:
- dekt alles — het kleinste blok dat je hele wens omvat (pakt er onderaan wat bij)
- past binnen — het grootste blok dat volledig binnen je wens valt
Bij .200 t/m .254 levert dat 10.0.20.192/26 op: 62 adressen, .193 t/m
.254. Klikken vult het veld in.
v0.5.42-beta — Netwerk toevoegen: twee blokkades weg
Een netwerk aanmaken lukte niet, met wisselend gedrag: soms een foutmelding dat de IP-range buiten het subnet lag terwijl dat aantoonbaar niet zo was, soms geen melding maar toch geen resultaat. Het bleken twee losse oorzaken.
De foutmelding die niet klopte
De beoordeling gaat af bij elke toetsaanslag. Tijdens het intypen van /28 ga
je langs /2, en 10.0.20.240/2 normaliseert naar 0.0.0.0/2 — inderdaad
buiten je subnet. Kwam dat antwoord ná het antwoord voor de volledige waarde
binnen, dan bleef die foutmelding staan en bleef de knop uitgeschakeld.
Er zit nu een volgnummer op: alleen het antwoord bij de laatste vraag telt. En de knop wordt niet meer uitgeschakeld op de clientstatus — bij het opslaan beslist de server, zodat een verouderde beoordeling je nooit kan blokkeren.
De range die Docker weigerde
10.0.20.200/28 heeft hostbits gezet. Python leest dat soepel als
10.0.20.192/28, maar Docker is streng en antwoordt "has host bits set". Wij
valideerden soepel en stuurden vervolgens de ruwe tekst door, dus de interface
keurde iets goed dat bij het aanmaken alsnog strandde.
Subnet en IP-range worden nu omgezet naar hun canonieke vorm voordat ze naar
Docker gaan én voordat ze worden opgeslagen, met een waarschuwing die laat zien
wat er van je invoer gemaakt is. .200/28 is trouwens een logische invoer — je
bedoelt "vanaf .200" — maar een /28 begint nu eenmaal op een veelvoud van 16.
v0.5.41-beta — Netwerk toevoegen liep vast tijdens het typen
Een netwerk toevoegen gaf een JSON-parsefout in de browser.
Oorzaak: de live beoordeling die bij elke toetsaanslag afgaat, bouwde een lijst
van alle bruikbare adressen in het bereik. Tijdens het intypen van
192.168.1.0/24 is de tussenstand 192.168.1.0/2 een volkomen geldig
netwerk — met 1.073.741.824 adressen. Het verzoek liep daarop vast en de browser
kreeg geen JSON meer terug.
review()rekent eerste adres, laatste adres en aantal nu uit in plaats van ze op te sommen. Antwoord binnen 0,05 seconde bij elk prefix.suggest_range()had hetzelfde probleem: die somde alle /28-blokken op, wat bij een/8ruim een miljoen blokken zijn. Rekent nu van achteren naar voren.- Waarschuwing bij een bereik van meer dan 4096 adressen, want dat is vrijwel altijd een typefout in het prefix.
- Ook
.envvan de deploy-map werd bij elke deploy gewist doorrsync --delete, omdat het bestand in.gitignorestaat en dus niet in de checkout zit. Daardoor raakte jeBINDtelkens kwijt.--exclude='.env'toegevoegd. - Nieuw
.env.examplemet alle instellingen bij elkaar en uitleg per sleutel.
v0.5.40-beta — Netwerken instellen zonder uitzoekwerk
🔍 Automatische detectie
Bij Instellingen → Netwerken → Netwerk toont Server Up nu bovenaan het netwerk dat je server zelf gebruikt: interface, subnet, gateway en een voorgestelde vrije IP-range. Eén klik vult het hele formulier.
De detectie start heel kort een container die de netwerknamespace van de host
deelt en leest daar de routetabel. Dat is nodig omdat Server Up in een eigen
namespace zit: de vorige versie las /sys/class/net binnen de container en
toonde daardoor de bridge-interface van de container zelf in plaats van de
netwerkkaart van de host — een lijstje dat er goed uitzag maar niet klopte.
Lukt detecteren niet (geen docker-socket, ouder image), dan staat er een nette melding en vul je het als vanouds handmatig in.
💡 Live meedenken bij het invullen
Terwijl je typt controleert Server Up de combinatie en toont wat het oplevert: "14 adressen beschikbaar: 192.168.1.241 tot en met 192.168.1.254". Klopt er iets niet, dan staat er in gewone taal bij waarom — een range buiten het subnet, een gateway die je beter buiten het bereik kunt houden, of een range zo klein dat er maar een paar stacks in passen.
Een knop stelt een vrij blok voor op basis van het subnet, met de gateway ontweken.
📖 Uitleg waar je hem nodig hebt
In het formulier zit een uitklapbaar blok dat uitlegt hoe subnet, gateway,
IP-range en host-interface zich tot elkaar verhouden, met een concreet voorbeeld.
docs/netwerken.md heeft dezelfde uitleg met een schema van de adresverdeling,
een tabel met veelgebruikte ranges, en één punt dat er echt uit moet springen:
het instellen van de IP-range in Server Up doet niets aan je router — je moet
daar zelf het DHCP-bereik verkleinen, anders blijven dubbele adressen mogelijk.
v0.5.30-beta — Rollen, app-store-filter en twee planningsfouten
👥 Rollen per gebruiker
Tot nu toe had elk account volledige toegang. Nu drie rollen:
| Rol | Mag |
|---|---|
| Beheerder | alles |
| Operator | stacks, containers en backups beheren — niet de instellingen, gebruikers, repo's, netwerken of modules |
| Alleen lezen | alleen bekijken |
- Afgedwongen in de
before_request-guard, niet alleen in de interface. - Je eigen wachtwoord wijzigen mag iedereen, ongeacht rol.
- De laatste beheerder kan niet gedegradeerd of verwijderd worden.
- Wie via de reverse proxy binnenkomt zonder eigen account krijgt de rol uit
AUTH.proxy_role; bestaat er wél een lokaal account met die naam, dan wint dat account. - Accounts van vóór deze versie hebben geen rol en gelden als beheerder.
🔒 Rechtenescalatie verholpen
Bij het wijzigen van een wachtwoord werd het hele gebruikersrecord vervangen,
waardoor het role-veld wegviel. Omdat een ontbrekende rol als beheerder geldt
(nodig voor bestaande accounts), kon elke operator of viewer zichzelf tot
beheerder promoveren door zijn eigen wachtwoord te wijzigen. Gevonden bij het
naspelen van de rollenflow; de rol blijft nu behouden en een test dekt het af.
⏰ Geplande backups draaiden nooit
De scheduler stempelde ook taken af die zichzelf hadden overgeslagen. De backup-taak bewaakt zelf of het het ingestelde uur is, dus die werd afgestempeld op het moment van de eerste tick — waarna het volgende moment 24 uur later op precies dat verkeerde tijdstip viel. Resultaat: de geplande backup kwam nooit aan de beurt.
Een taak stempelt nu alleen af als hij True teruggeeft. De backup-taak draait
daardoor op een kort interval en bepaalt zelf wanneer het zover is, zodat een
gewijzigde planning ook meteen werkt zonder herstart. Voor wekelijkse backups is
BACKUP_SCHEDULE_DAY toegevoegd.
🔎 Zoeken en filteren in de app store
Zoekveld over naam, omschrijving en tags, plus klikbare tagfilters (de veertien meestgebruikte, op frequentie gesorteerd). Repo's zonder treffers vallen weg.
🔧 Overig
- Opstartcontrole op de meegeleverde front-end-bestanden. Mislukt het downloaden tijdens de image-build, dan laadde de interface zonder opmaak terwijl de server prima leek te draaien; nu staat er een duidelijke melding in het log.
- 227 tests.
v0.5.20-beta — Vertalingen, SSO-scherm, complete backups en app-updates
🌍 Vertalingen en SSO
- De schermen uit v0.5.x (login, Beveiliging, Netwerken, Updates,
containerpaneel) gebruikten harde Nederlandse teksten terwijl de rest van de
interface via
t()loopt. Op Engels gaf dat een mengelmoes. Nu volledig vertaald: 208 sleutels innlenen. t()ondersteunt plaatshouders:t('port_taken', {port: 8080}). Zo blijven zinnen heel in plaats van in losse stukjes geknipt.- Nieuw instelscherm voor reverse-proxy-SSO onder Instellingen →
Beveiliging: modus lokaal/proxy/beide, identiteitsheader en de vertrouwde
proxy-adressen. De backend bestond al maar was alleen met
curlte bereiken. - Nieuwe test bewaakt dat
nlenendezelfde sleutels houden, dat de plaatshouders in beide talen gelijk zijn, en dat de interface geen sleutels gebruikt die nergens gedefinieerd staan.
💾 Backups compleet
Backup was één tar-commando waarvan de returncode genegeerd werd — een
mislukte backup gold als succes, en terugzetten kon alleen met de hand.
- Terugzetten met één klik: stack stoppen, huidige map opzij, uitpakken, starten. Mislukt het uitpakken, dan komt de oude situatie terug.
- Bewaarbeleid: aantal per stack en/of maximale leeftijd. De nieuwste backup van een stack blijft altijd staan.
- Geplande backups, dagelijks of wekelijks, via een eigen planner in de applicatie (geen cron). Een gemiste ronde loopt bij de eerstvolgende gelegenheid alsnog.
- Automatisch een backup vóór het bijwerken of verwijderen van een stack. Mislukt die, dan gaat de actie door — anders kun je een kapotte stack niet meer opruimen.
- Uitpakken gebeurt met
tarfileenfilter="data": absolute paden en..-ingangen worden geweigerd. Met een kaaltar xzfkon een geprepareerd archief buiten de stackmap schrijven. - Backups binnen dezelfde seconde overschreven elkaar; namen krijgen nu een teller.
docs/backups.mdlegt uit wat er wél en niet in zit — de compose- en.env-bestanden, niet de Docker-volumes met de eigenlijke appdata.
📦 Updates per app
- Server Up controleert nu ook of er nieuwere images zijn voor de geïnstalleerde stacks, met een badge op de stackkaart en een knop om te controleren. Bijwerken doet de bestaande update-knop.
- De vergelijking loopt via de Registry API v2 (
Docker-Content-Digest), niet viadocker manifest inspect: dat laatste geeft per platform een aparte digest terug terwijlRepoDigestsde digest van de manifest-list bevat, wat bij elk multi-arch image permanent "update beschikbaar" zou opleveren. - Drie statussen per service —
update,currentenunknown. Een lokaal gebouwd image, een nog niet gepulld image of een onbereikbare registry levertunknownop en dus géén badge, zodat er nooit ten onrechte een update wordt gemeld. - Dagelijkse achtergrondcheck via dezelfde planner; resultaten 6 uur gecached.
v0.5.10-beta — Update-systeem met kanalen en één-klik bijwerken
🔄 Kanalen
Server Up kent nu twee update-kanalen in plaats van een vinkje "pre-releases meenemen":
- stable — alleen echte releases (
v0.5.10) - beta — ook pre-releases (
v0.5.10-beta1), dierelease.ymlautomatisch als zodanig markeert bij een tag met een streepje
Een release telt hoger dan zijn eigen beta (0.5.10-beta1 < 0.5.10), dus wie
op beta zit krijgt de definitieve versie alsnog aangeboden. De oude instelling
UPDATE_INCLUDE_PRERELEASE migreert automatisch naar het beta-kanaal.
⬇️ Bijwerken vanuit de interface
Nieuw: Nu bijwerken haalt het image uit je Forgejo container-registry en vervangt de eigen container.
- Omdat een container zichzelf niet kan hercreëren, doet Server Up alleen het
voorwerk (image ophalen,
SU_TAGwegschrijven) en laat het de hercreatie over aan een korte helper-container die op het nieuwe image draait — dat bevat de docker- en compose-CLI al. - De deploy-map wordt uitgelezen uit de compose-labels van de eigen container, niet geraden. Ontbreken die labels, draait de container niet vanaf een registry-image, of is de docker-socket er niet, dan meldt de interface precies waaróm bijwerken niet kan in plaats van iets te proberen.
- De vorige tag wordt onthouden, met een terugrolknop in de instellingen.
- Voortgang van de
docker pullloopt via het bestaande job-logvenster; daarna pollt de browser/healthztot de nieuwe versie leeft.
🔧 Overig
- Update-check wordt een uur gecached; Controleren forceert een verse check. Eerder deed elke paginalading een netwerkverzoek.
- Laatst-gecontroleerd-tijdstip zichtbaar in de interface.
- Registry-inloggegevens instelbaar voor een privé registry. Het token wordt net
als de git-tokens nooit teruggegeven door de API (alleen een
has_-vlag) en leeg laten betekent "ongewijzigd". docker-compose.ymlgebruikt${SU_IMAGE:-server-up}:${SU_TAG:-latest}, zodat image en tag los instelbaar zijn. ZonderSU_IMAGEblijft alles werken zoals voorheen (lokaal bouwen).deploy-prod.ymlbouwt én pusht het image in dezelfde job wanneerSU_IMAGEingesteld is. Bewust niet als aparte workflow: bij één runner zou de deploy wachten op een build die zelf nog in de wachtrij staat.build.ymlis nu alleen handmatig, voor het herbouwen van een specifieke tag.docs/updates.mdtoegevoegd: hoe het werkt, de complete Forgejo-instelling (registry, tokens, variables, secrets, runners), de release-procedure voor zowel stable als beta, terugrollen en een probleemoplostabel.
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.1gebonden; zetBIND=0.0.0.0in je.envals je er van buiten de server bij moet (liefst achter een reverse proxy met TLS — ziedocs/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 geenGETmeer —/api/docker/restartwas eerder met een<img>-tag vanaf een willekeurige website te triggeren. - Path traversal:
/api/store/installcontroleerde de instantienaam niet;"instance": "../../…"schreef buiten de library. Alle stack-, instantie- en repo-namen lopen nu door éénsafe_name()-validatie. - Tokenlek: git-tokens werden teruggegeven door
/api/reposen/api/settings. Die zijn vervangen door eenhas_token-vlag; opslaan met een leeg veld wist het bestaande token niet meer. - Git-URL's: alleen
http(s)://,ssh://engit@host:pad. Git'sext::-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 stondStrictHostKeyChecking=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.jsonen 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_addresserin. De templates inapps/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
/healthzvoor de healthcheck in plaats vandocker info. fix-config.shverwijderd: 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, toontv0.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
docker compose build --no-cache
docker compose up -d
v0.3.0 — UI rebuild + Boilerplates support
Hoogtepunten
🎨 Nieuwe UI (Tailwind + Alpine + HTMX)
templates/index.htmlis 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)— detectiemetadata(d)— converteerttemplate.json["metadata"](incl. selfhst-icons) naar Server-Up formaatfields(d)— flattened variable-schema voor de install-modalrender_to_dir(src, dest, values)— rendertfiles/*.yamlmet 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_srcaccepteert ook boilerplate-mappen.POST /api/store/previewretourneert voor boilerplates het variabelen-schema (fields) plus een gerenderde preview met defaults.POST /api/store/installmet 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:
bes-r/server-up— eigen stacks, submapappsChristianLempa/boilerplates-library— community templates, submapcompose
📦 Versie / Dockerfile
SU_VERSION=0.3.0inDockerfileendocker-compose.ymlrequirements.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.