214 lines
12 KiB
Markdown
214 lines
12 KiB
Markdown
# Appstore - masterplan
|
||||
|
|
|
|||
|
|
> **Status: nog niet actief.** Dit is één bestand en dat is bewust: er is nog geen `TAKEN.md`,
|
|||
|
|
> `PROGRESS.md` of `OPEN.md`, want er wordt nog niet aan gewerkt. Bij promotie naar
|
|||
|
|
> `Plannen/Actief/NNN-Appstore/` worden de paragrafen hieronder over die vier bestanden verdeeld; zie
|
|||
|
|
> `HomeGit/Docs/Werkproces.md` §1b.
|
|||
|
|
>
|
|||
|
|
> Afhankelijk van: –
|
|||
|
|
|
|||
|
|
## 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. De repo staat op de eigen
|
|||
|
|
Git-server, `https://sc.kamenier-hamer.nl/sysop/ElectrumTLS.git`, en dat kan: umbreld doet geen enkele
|
|||
|
|
controle op de hostnaam. Zie §4e voor wat dat wél afdwingt.
|
|||
|
|
|
|||
|
|
## 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](../../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.
|
|||
|
|
Wel een harde koppeling: **de repo gaat pas naar GitHub als Configuratie af is**, want anders staat een
|
|||
|
|
persoonlijk domein en de indeling van een privé-server in een publieke repo. Zie open punt 3.
|
|||
|
|
- **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
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
ElectrumTLS/
|
|||
|
|
├── umbrel-app-store.yml id: electrumtls
|
|||
|
|
├── electrumtls-electrum-tls/
|
|||
|
|
│ ├── umbrel-app.yml id: electrumtls-electrum-tls
|
|||
|
|
│ ├── docker-compose.yml
|
|||
|
|
│ ├── entrypoint.sh
|
|||
|
|
│ └── web/index.html
|
|||
|
|
├── Docs/
|
|||
|
|
├── README.md
|
|||
|
|
└── CHANGELOG.md
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
De store-id is `electrumtls`, gekozen op 18-08-2026. De prefix-eis is hard: mapnaam en manifest-`id`
|
|||
|
|
moeten gelijk zijn en allebei met de store-id beginnen.
|
|||
|
|
|
|||
|
|
### 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:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
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 GitHub Actions-workflow die multi-arch naar GHCR
|
|||
|
|
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;
|
|||
|
|
- 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.
|
|||
|
|
|
|||
|
|
### 4e. De eigen Git-server als app store
|
|||
|
|
|
|||
|
|
De repo komt op `https://sc.kamenier-hamer.nl/sysop/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 wat dus getest moet worden:
|
|||
|
|
|
|||
|
|
- **HTTPS, niet SSH.** De URL hierboven heeft de goede vorm.
|
|||
|
|
- **Anoniem kloonbaar.** umbreld geeft geen inloggegevens mee, dus de repo moet in Gitea op publiek
|
|||
|
|
staan. Een privérepo werkt niet, en er is geen omweg.
|
|||
|
|
- **Geldig certificaat op `sc.kamenier-hamer.nl`.** Node valideert de keten. Loopt die host al via
|
|||
|
|
Zoraxy met Let's Encrypt, dan is dit in orde, maar het is het controleren waard voordat het klonen
|
|||
|
|
onverklaarbaar faalt.
|
|||
|
|
- **Alles op de standaardbranch.** Er wordt met `depth: 1, singleBranch: true` gekloond, dus een tag of
|
|||
|
|
tweede branch levert niets op.
|
|||
|
|
- **De URL is de identiteit van de store.** Wijzigt hij, dan ziet umbrelOS een andere store en moet hij
|
|||
|
|
opnieuw toegevoegd worden. Kies hem dus één keer goed.
|
|||
|
|
|
|||
|
|
### 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.
|
|||
|
|
|
|||
|
|
## 5. Het werk in grote lijnen
|
|||
|
|
|
|||
|
|
**Fase 1 - De repo-vorm.** `umbrel-app-store.yml` erbij, de app-bestanden naar
|
|||
|
|
`electrumtls-electrum-tls/`, het app-id met prefix, `install.sh` en `uninstall.sh` eruit. Uitkomst: de
|
|||
|
|
repo heeft de vorm die umbrelOS herkent.
|
|||
|
|
|
|||
|
|
**Fase 2 - De compose.** `app_proxy` erin, het externe `umbrel_main_network` en de handmatige
|
|||
|
|
`APP_..._PORT`-plaatshouders eruit, de mounts op `${APP_DATA_DIR}` en `${UMBREL_ROOT}`. Uitkomst: een
|
|||
|
|
compose die umbrelOS zelf kan draaien.
|
|||
|
|
|
|||
|
|
**Fase 3 - Backend-onafhankelijk.** `dependencies: [electrs]` en `${APP_ELECTRS_NODE_IP}` /
|
|||
|
|
`${APP_ELECTRS_NODE_PORT}`. Uitkomst: de app werkt met Electrs, Fulcrum en ElectrumX zonder aanpassing.
|
|||
|
|
|
|||
|
|
**Fase 4 - De image.** `nginx:alpine` gepind op digest, `stream`-configuratie in plaats van stunnel,
|
|||
|
|
`cert-monitor` samengevoegd en de Docker-socket eruit. Uitkomst: één gepinde container, geen `apk add`
|
|||
|
|
bij start, geen socket.
|
|||
|
|
|
|||
|
|
**Fase 5 - Het manifest.** Eigen icoon en gallery in de repo, `port` op de web-UI-poort, `developer`,
|
|||
|
|
`repo`, `support`, `submitter` en `submission` kloppend, `website` naar de eigen repo. Uitkomst: een
|
|||
|
|
tegel die er klopt uitziet en niet naar andermans plaatjes wijst.
|
|||
|
|
|
|||
|
|
**Fase 6 - Installeren en verifiëren.** Store toevoegen in umbrelOS, installeren, en de dingen nalopen
|
|||
|
|
die alleen op het apparaat te zien zijn: start hij mee na een herstart, komt hij terug als Electrs
|
|||
|
|
omvalt, en werkt de TLS-verbinding vanaf een echte wallet.
|
|||
|
|
|
|||
|
|
## 6. Open punten
|
|||
|
|
|
|||
|
|
1. **Draait `nginx:alpine` met de `stream`- en `stream_ssl`-module?** De hele keuze uit §4c hangt hierop.
|
|||
|
|
**Moment:** als eerste taak van fase 4, vóór er iets herschreven wordt. **Eigenaar:** uitvoerder.
|
|||
|
|
|
|||
|
|
2. **Wat gebeurt er met een bestaande installatie?** Er draait nu een handmatig neergezette
|
|||
|
|
`electrum-tls` op de Umbrel. Die moet met de hand weg voordat de echte app geïnstalleerd wordt, anders
|
|||
|
|
vecht hij om de poort. Hoort daar een korte migratie-aanwijzing bij in de README, of doet de gebruiker
|
|||
|
|
dat eenmalig zelf? **Moment:** bij fase 6. **Eigenaar:** gebruiker.
|
|||
|
|
|
|||
|
|
3. **Wanneer wordt er voor het eerst gepusht?** **Beslist op 18-08-2026: meteen.** De repo staat sinds
|
|||
|
|
die dag publiek op `https://sc.kamenier-hamer.nl/sysop/ElectrumTLS.git`, met de
|
|||
|
|
installatiespecifieke waarden er nog in. Dat de repo publiek moest, stond niet ter discussie: umbreld
|
|||
|
|
kloont anoniem. Alleen de volgorde was een keuze, en die is bewust vóór **Configuratie** gevallen.
|
|||
|
|
|
|||
|
|
Het gevolg dat vastligt: **`sync.kamenier-hamer.nl` en het certificaatpad staan nu in de publieke
|
|||
|
|
historie.** Ze eruit halen in Configuratie haalt ze uit de bestanden, niet uit de historie; daarvoor
|
|||
|
|
zou de historie herschreven moeten worden, en dat is bij een repo die anderen al gekloond kunnen
|
|||
|
|
hebben geen schoonmaak maar een breuk. Behandel het domein dus als bekend, en laat het geen argument
|
|||
|
|
worden om Configuratie uit te stellen: de winst daarvan zit nu in herbruikbaarheid, niet meer in
|
|||
|
|
geheimhouding.
|
|||
|
|
|
|||
|
|
4. **Eigen icoon.** Het manifest wijst nu naar het Electrs-icoon in andermans repo. Er moet een eigen
|
|||
|
|
SVG komen en een gallery-plaatje. Wie maakt die, en waar staan ze (in de repo of extern gehost)?
|
|||
|
|
**Moment:** fase 5. **Eigenaar:** gebruiker.
|
|||
|
|
|
|||
|
|
## 7. 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.
|