Files
UmbrelApps/Docs/Plannen/Actief/010-Appstore/PLAN.md
T
HarmenandClaude Opus 5 67ed9b603b Eén app store, twee apps
umbrelOS leest per store één repo, dus twee apps in twee repo's kan niet. Deze
repo is de store en bevat vanaf nu Electrum Gate en het werk aan Evolu Relay.
Opgezet als verse repo op verzoek van de gebruiker: de historie van ElectrumTLS
en van EvoluRelay komt niet mee.

Dat heeft één gevolg dat verder gaat dan opruimen. In de historie van
ElectrumTLS staat het domein van de gebruiker en het certificaatpad, van vóór de
opschoning van 19-08. Die komt hier niet in. Zolang die repo op de Git-server
blijft staan verandert dat niets, dus het weghalen ervan is het laatste stuk van
open punt 3 van het plan Appstore, en geen bijzaak.

De store zelf hoefde niet te veranderen: store-id whatsnext, en dus blijft het
app-id whatsnext-electrum-gate. Dat hangt aan het store-id en niet aan de URL,
dus voor umbrelOS is dit dezelfde app in een andere store. Dat de store op 19-08
naar de maker genoemd werd in plaats van naar deze ene app, betaalt zich hier
uit.

Wat de documentatie betreft is dit één wortel voor beide apps, en dat was de
reden om samen te voegen en niet de prijs ervan: de appstore-spec, het pinnen
van images en de werkwijze golden al voor allebei en stonden in twee repo's naast
elkaar. De kruisverwijzing die daarvoor nodig was (Referenties/Umbrel-appstore.md
in de oude EvoluRelay-repo) is verdwenen; wat daarin stond over de plekken waar
de relay een ander geval is, staat nu als ontwerp in het masterplan Umbrelapp §4.

Botsende namen kregen een achtervoegsel met de app, en alleen die: Publicatie
werd Publicatie-Gate en Publicatie-Relay, CHANGELOG.md werd
CHANGELOG-electrum-gate.md. Proefopstelling kreeg 007, tussen de twee bestaande
nummers, zodat de bovenkant van de reeks op tier-orde blijft staan.
CONTINUE_HERE.md heeft een kolom App, maar de tiers lopen over beide apps heen:
er is één volgorde van werken.

Electrum Gate gaat naar 0.0.15, want website, repo, support, submission en icon
wijzen nu naar UmbrelApps en zonder versieverhoging rolt dat niet uit. De release
notes leggen aan de gebruiker uit dat hij de store opnieuw moet toevoegen. Of een
geïnstalleerde app een wisseling van store-URL overleeft is nog steeds niet
uitgezocht; dat blijkt bij het omzetten.

Twee dingen in de plannen van Electrum Gate waren door deze verhuizing niet meer
waar en zijn bijgewerkt: de taak "de repo hernoemen" in fase 7 is afgevinkt, en
de repo-vorm in PLAN.md §4a toonde nog de store-id electrumtls, die al sinds
fase 7 achterhaald was.

Tests: 39 goed 0 fout en 54 goed 0 fout, niets overgeslagen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 16:27:57 +02:00

10 KiB

Appstore - plan

Ontwerp en afbakening. Dit bestand lees je zelden, alleen bij twijfel over scope of architectuur. Status staat in TAKEN.md, geschiedenis in PROGRESS.md, onbesliste punten in OPEN.md.

1. Doel

De app draait nu als een met de hand neergezette docker-compose die umbrelOS niet kent. Gevolg: na een herstart van de Umbrel, of als een app waar deze van afhangt omvalt, moet er met de hand docker compose down en up gedaan worden. Dit plan maakt er een echte Umbrel-app van in een eigen community app store: een tegel met icoon, die umbrelOS zelf installeert, start en na een herstart weer opbrengt.

Als dit af is, is de repo tegelijk de app store: de URL erin plakken in umbrelOS is genoeg om de app te installeren, en een git push is genoeg om een update uit te leveren.

2. Afbakening

  • De repo omzetten naar de vorm die umbrelOS voor een community app store verwacht.
  • docker-compose.yml omzetten naar de moderne vorm: app_proxy, geen zelfgebouwd netwerk, geen handmatige host-poorten waar dat niet hoeft.
  • De Electrum-backend via de afhankelijkheid aanspreken in plaats van via een hardgecodeerde containernaam, zodat Electrs, Fulcrum en ElectrumX alle drie werken.
  • Een image die gepind kan worden, in plaats van alpine:latest met apk add bij elke start.
  • Het manifest compleet en eerlijk maken: eigen icoon, eigen gallery, kloppende velden.
  • De oude install.sh en uninstall.sh weghalen.

De volledige spec waar dit tegenaan moet, met bronvermelding per feit, staat in Referenties/Umbrel-appstore-spec.md. Die is bij het schrijven van dit plan uitgezocht en hoeft niet opnieuw opgezocht te worden.

3. Niet-doelen

  • De hardgecodeerde waarden eruit halen. Het domein sync.kamenier-hamer.nl en het Zoraxy-pad blijven in dit plan staan zoals ze zijn. Dat is het plan Configuratie, en het apart houden is bewust: een commit die tegelijk de structuur omgooit en de configuratie herontwerpt is niet meer na te lezen.
  • De web-UI eerlijk maken. De pagina toont verzonnen status. Dat is het plan Webinterface. Hier wordt de pagina alleen verhuisd en aan app_proxy gehangen, niet herschreven.
  • Meerdere apps in de store. De store krijgt de vorm die meer apps toelaat, maar er komt er één in.
  • Indienen bij de officiële Umbrel App Store. Een community store is er juist om dat niet te hoeven. Als het later toch aantrekkelijk wordt, is de spec-eis grotendeels dezelfde, dus dit sluit niets af.

4. Ontwerp

4a. De repo-vorm

UmbrelApps/
├── umbrel-app-store.yml              id: whatsnext
├── whatsnext-electrum-gate/
│   ├── umbrel-app.yml                id: whatsnext-electrum-gate
│   ├── docker-compose.yml
│   ├── *.template
│   └── data/{certs,runtime}/.gitkeep
├── whatsnext-evolu-relay/            komt er bij het masterplan Umbrelapp
├── Docs/
├── tests/
└── README.md

De store-id is whatsnext. De prefix-eis is hard: mapnaam en manifest-id moeten gelijk zijn en allebei met de store-id beginnen.

Bijgewerkt op 25-08-2026, toen de repo een store met meer dan één app werd. Hier stond nog de vorm van 18-08-2026 met store-id electrumtls; die was al achterhaald door fase 7. Wat de tweede app bewijst is dat de keuze van 19-08 om de store naar de maker te noemen in plaats van naar deze ene app, klopte: er hoefde niets voor te hernoemen.

4b. Backend-onafhankelijk, en waarom dat bijna niets kost

umbrelOS 1.3 heeft swappable dependencies. Fulcrum en ElectrumX declareren allebei implements: [electrs] en hun exports.sh aliast APP_ELECTRS_IP, APP_ELECTRS_NODE_IP en APP_ELECTRS_NODE_PORT naar hun eigen waarden. De gebruiker kiest de implementatie in de umbrelOS-instellingen; umbrelOS laadt de exports.sh van de gekozen app.

Deze app hoeft daarvoor dus geen keuzemechanisme te bouwen. Het is dit:

dependencies:
  - electrs

en in de compose ${APP_ELECTRS_NODE_IP}:${APP_ELECTRS_NODE_PORT} gebruiken.

Twee vallen om te vermijden. De eerste: de huidige compose zet ELECTRS_HOST=${APP_ELECTRS_IP}, en dat is de web-UI-container van Electrs, niet de Electrum-server; dat moet APP_ELECTRS_NODE_IP worden. De tweede: alleen IP, NODE_IP en NODE_PORT worden gealiast, dus alles wat Electrs-specifiek is (zoals APP_ELECTRS_RPC_HIDDEN_SERVICE) mag hier niet gebruikt worden.

4c. De image: nginx stream in plaats van stunnel

Het huidige alpine:latest plus apk add stunnel bij elke start is op drie manieren fout: het is niet te pinnen, het faalt zonder internet, en het maakt de starttijd afhankelijk van een Alpine-mirror. De app-store-eis is een image gepind op de multi-arch index-digest.

Er zijn drie wegen, en de aanbeveling is de derde:

  1. Eigen image bouwen met een Dockerfile en een workflow die multi-arch naar een registry duwt. Correct, maar het voegt CI, een registry en een tweede uitleverstroom toe aan een app die verder uit twee shellscripts bestaat.

  2. Een bestaande stunnel-image pinnen. Er is geen onderhouden multi-arch stunnel-image die het vertrouwen waard is. Afgevallen.

  3. De officiële nginx-image gebruiken en de stream-module de TLS-terminatie laten doen. Die image is multi-arch, wordt onderhouden en is gewoon te pinnen. Dan valt er meer weg dan alleen het bouwprobleem:

    • dezelfde container serveert de web-UI én termineert TLS, dus van drie containers blijft er één over. Bijgesteld 19-08-2026: het zijn er weer twee, want er is een agent bijgekomen. De winst die hier bedoeld werd blijft wel staan: geen Docker-socket, geen installatie bij het starten, en de certificaatwissel is een reload. Zie het plan Webinterface, PLAN.md §4a0;
    • een certificaatwissel wordt nginx -s reload binnen de container, dus de cert-monitor heeft de Docker-socket niet meer nodig. Die socket is nu read-only gemonteerd, maar read-only op de Docker-socket beschermt niets: wie de socket kan lezen kan containers starten en is daarmee root op de host. Dat weghalen is de grootste beveiligingswinst in dit plan;
    • een reload verbreekt bestaande verbindingen niet, een containerherstart wel.

    Te verifiëren voordat hierop gebouwd wordt: dat de officiële nginx:alpine daadwerkelijk met --with-stream en --with-stream_ssl_module gebouwd is. Dat is de aanname waar deze hele keuze op rust en hij is in één commando te controleren (nginx -V). Klopt hij niet, dan valt dit terug op weg 1.

De awk-splitsing van de certificaat-chain uit entrypoint.sh blijft bruikbaar en wordt overgenomen.

4d. Poorten

port: in het manifest is de web-UI-poort van de tegel, niet de TLS-poort. Dat staat nu op 50002 en is daarmee fout.

De TLS-poort blijft een gepubliceerde host-poort; daar helpt app_proxy niet, want dat is voor HTTP. Welke poort dat wordt is een open punt in Configuratie: Fulcrum bezet host-poort 50002 en botst dus met de huidige keuze.

4e. De eigen Git-server als app store

De repo staat op https://sc.kamenier-hamer.nl/sysop/UmbrelApps.git (tot 25-08-2026: .../ElectrumTLS.git). umbreld valideert de URL alleen met de URL-constructor en kloont met isomorphic-git; er is geen GitHub-eis. Wat er wél uit die aanroep volgt, en op 18-08-2026 in orde is bevonden:

  • HTTPS, niet SSH. In orde.

  • Anoniem kloonbaar. In orde sinds 18-08-2026, maar het kostte moeite en de oorzaak was niet de voor de hand liggende.

    umbrelOS gaf HTTP Error: 401 Unauthorized bij het toevoegen van de store. De repo stond op public en REQUIRE_SIGNIN_VIEW stond op false, en toch weigerde Gitea. De oorzaak was de zichtbaarheid van het account sysop, die op "limited" stond. Gitea staat niet toe dat een repo zichtbaarder is dan zijn eigenaar, dus de repo werd stilzwijgend teruggezet naar "intern", wat voor een niet-ingelogde bezoeker hetzelfde is als privé. De knop "make public" leek te werken maar het label bleef op "intern" staan, en dat is het enige zichtbare spoor.

    Dit is eerst verkeerd beoordeeld, en de manier waaróp is het onthouden waard. Een git ls-remote vanaf de werkmachine slaagde, ook met GIT_TERMINAL_PROMPT=0, en dat leek bewijs van anonieme toegang. Het was het niet: Git Credential Manager stuurde de bij de push opgeslagen inloggegevens stilzwijgend mee. GIT_TERMINAL_PROMPT=0 onderdrukt alleen de vraag om een wachtwoord, niet het aanleveren ervan. De test die het wel aantoont, zet de credential-helper leeg:

    GIT_TERMINAL_PROMPT=0 git -c credential.helper= ls-remote <url>
    

    Die faalt met could not read Username, en dat is de toestand die umbreld ziet.

  • SHA-1 als objectformaat. In orde, na het opnieuw aanmaken van de repo. isomorphic-git kan geen SHA-256; zie de naslag.

  • Geldig certificaat op sc.kamenier-hamer.nl. Nog niet expliciet gecontroleerd vanaf de Umbrel.

  • Alles op de standaardbranch. In orde: main, zowel lokaal als op de remote.

  • De URL is de identiteit van de store. Wijzigt hij, dan ziet umbrelOS een andere store en moet hij opnieuw toegevoegd worden.

5. Raakvlakken

Configuratie herschrijft dezelfde bestanden en wacht op dit plan. Twee dingen komen daarvandaan terug: de TLS-poort (open punt daar, want Fulcrum bezet 50002) en het feit dat het domein na dit plan nog steeds vast in de code staat.

Webinterface wacht op Configuratie en raakt hier alleen de verhuizing van web/index.html. Het containerontwerp uit §4c is wel de reden dat dat plan zonder backend kan: de proxy en de webserver worden één container, dus als de pagina geserveerd wordt, draait de proxy ook.

6. Verificatie

Er zijn geen tests in dit project en die zijn hier ook niet zinvol: de app is configuratie, geen code. Wat er wél moet, en wat per se handmatig op het apparaat gebeurt:

  • de store laat zich in umbrelOS toevoegen en de app verschijnt met icoon en tegel;
  • installeren via de umbrelOS-interface werkt zonder SSH;
  • na sudo reboot komt de app vanzelf terug. Dit is de aanleiding voor het hele plan en dus de belangrijkste controle;
  • de app komt ook terug nadat Electrs handmatig gestopt en gestart is;
  • een Electrum-wallet verbindt over TLS en verifieert het certificaat;
  • omschakelen naar Fulcrum in de umbrelOS-instellingen laat de app werken zonder aanpassing.

Wat automatisch gecontroleerd kan worden, en de moeite waard is omdat het de fouten vangt die je niet ziet: dat de YAML geldig is, dat het id in het manifest gelijk is aan de mapnaam, en dat elke image: een @sha256:-digest heeft.