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>
248 lines
13 KiB
YAML
248 lines
13 KiB
YAML
services:
|
|
# umbrelOS genereert deze service zelf; wij vullen alleen in waar hij heen moet
|
|
# wijzen. De hostnaam heeft de vorm <app-id>_<compose-service>_1.
|
|
app_proxy:
|
|
environment:
|
|
APP_HOST: whatsnext-electrum-gate_server_1
|
|
APP_PORT: 80
|
|
|
|
# De agent. Hij schrijft status.json, leest de certificaten, bevraagt de
|
|
# Electrum-server en neemt de certificaatkeuze aan.
|
|
#
|
|
# Waarom een tweede container en niet een shell-lus in de server hieronder:
|
|
# dit werk is inmiddels een programma. Een certificaatdatum uitlezen, een
|
|
# JSON-RPC-verzoek doen, een geschiedenis bijhouden en een keuze valideren zijn
|
|
# geen dingen die je met openssl en nc aan elkaar knoopt zonder dat het stil
|
|
# verkeerde antwoorden gaat geven. Bijkomend voordeel: de app hangt niet meer
|
|
# af van de vraag of die twee gereedschappen in de nginx-image zitten.
|
|
agent:
|
|
# TODO (fase 4 van het plan Appstore): pinnen op de multi-arch index-digest,
|
|
# te bepalen met `docker buildx imagetools inspect python:3-alpine` op de
|
|
# Umbrel. Geldt voor beide images in dit bestand.
|
|
image: python:3-alpine
|
|
restart: on-failure
|
|
environment:
|
|
# Het adres van de Electrum-server die de gebruiker in umbrelOS gekozen
|
|
# heeft. umbrelOS vult dit in op grond van de afhankelijkheid hieronder,
|
|
# dus dit werkt met Electrs, Fulcrum en ElectrumX.
|
|
GATE_ELECTRUM_HOST: ${APP_ELECTRS_NODE_IP}
|
|
GATE_ELECTRUM_PORT: ${APP_ELECTRS_NODE_PORT}
|
|
GATE_TLS_PORT: "50022"
|
|
GATE_INTERVAL: "60"
|
|
GATE_API_PORT: "8000"
|
|
GATE_STATE_DIR: /var/lib/gate
|
|
# Bron-naam=map. Een bron die niet gemount is, bestaat niet en wordt
|
|
# overgeslagen; dat is de normale toestand voor een reverse proxy die de
|
|
# gebruiker niet draait.
|
|
GATE_CERT_SOURCES: "Zoraxy=/certs/zoraxy,Own folder=/certs/own"
|
|
# De enige beschrijfbare bron, en dus de map waarin een upload van de
|
|
# pagina landt. Expliciet en niet afgeleid uit de lijst hierboven: welke
|
|
# bron beschrijfbaar is, hoort te staan naast de mount die dat toestaat.
|
|
# Leeg zetten schakelt uploaden uit.
|
|
GATE_UPLOAD_DIR: /certs/own
|
|
PYTHONUNBUFFERED: "1"
|
|
volumes:
|
|
# Door umbrelOS ingevuld uit agent.py.template bij het starten. Er staat
|
|
# geen accolade-variabele in dat bestand, dus de invulling laat de
|
|
# Python-code ongemoeid; de agent leest zijn instellingen uit de omgeving
|
|
# hierboven. De test in tests/ controleert die aanname.
|
|
- ${APP_DATA_DIR}/agent.py:/app/agent.py:ro
|
|
# De gedeelde toestand: status.json, cert.conf, de herlaadvlag en de
|
|
# gekozen certificaat-id. Beide containers zitten hierin.
|
|
#
|
|
# Onder data/ en niet naast de templates, want dat is wat andere apps doen:
|
|
# electrs mount ${APP_DATA_DIR}/data/electrs, mempool ${APP_DATA_DIR}/data.
|
|
# Verplaatst op 20-08-2026 met het oog op publicatie in de officiele store.
|
|
- ${APP_DATA_DIR}/data/runtime:/var/lib/gate
|
|
# De certificaatbronnen. Zoraxy alleen lezen: dat zijn de certificaten van
|
|
# een andere app en die raakt deze app niet aan.
|
|
- ${UMBREL_ROOT}/app-data/zoraxy/data/config/conf/certs:/certs/zoraxy:ro
|
|
# De eigen map is de enige die beschrijfbaar is, want hier landt een upload
|
|
# van de pagina. Alleen de agent; de nginx-container houdt hem alleen-lezen,
|
|
# want die hoeft er nooit iets neer te zetten.
|
|
- ${APP_DATA_DIR}/data/certs:/certs/own
|
|
#
|
|
# Nginx Proxy Manager hoort hier als derde bron bij en staat er bewust nog
|
|
# niet in. Het pad hieronder is een gok en niet geverifieerd, en een
|
|
# bind-mount naar een pad dat niet bestaat laat Docker het aanmaken. Dat zou
|
|
# een lege maphierarchie neerzetten in de app-data van een app die
|
|
# misschien niet eens geinstalleerd is, en die rommel blijft daar staan.
|
|
# Eerst op de Umbrel controleren waar NPM zijn certificaten neerzet, dan
|
|
# deze regel aanzetten en de naam toevoegen aan GATE_CERT_SOURCES.
|
|
#
|
|
# - ${UMBREL_ROOT}/app-data/nginx-proxy-manager/data/letsencrypt/live:/certs/npm:ro
|
|
command:
|
|
- python
|
|
- /app/agent.py
|
|
|
|
server:
|
|
image: nginx:alpine
|
|
restart: on-failure
|
|
# De agent moet er zijn voordat nginx start, want de proxy_pass naar
|
|
# http://agent:8000 wordt bij het starten opgelost en een onbekende naam
|
|
# laat nginx afbreken. Op de cert.conf van de agent wordt niet gewacht: de
|
|
# pagina komt hoe dan ook omhoog, zie het command-blok hieronder.
|
|
depends_on:
|
|
- agent
|
|
ports:
|
|
# De TLS-poort voor Electrum-wallets. Dit is de enige poort die deze app
|
|
# zelf publiceert; de web-UI loopt via app_proxy.
|
|
#
|
|
# 50022 en niet de conventionele 50002, omdat Fulcrum die op de host
|
|
# bezet: met Fulcrum als backend zou de container niet starten, en dat is
|
|
# precies het omschakelen dat deze app moet ondersteunen. De poort naar
|
|
# buiten is toch al een andere, want die staat in de router doorgestuurd.
|
|
# Beslist 19-08-2026, open punt 1 van het plan Configuratie.
|
|
- "50022:50022"
|
|
volumes:
|
|
# Beide door umbrelOS ingevuld uit een .template bij het starten. De
|
|
# pagina wordt als los bestand gemount en niet als map: de bron staat in
|
|
# de app-root, want alleen daar wordt hij bij een update ververst.
|
|
- ${APP_DATA_DIR}/nginx.conf:/etc/nginx/nginx.conf:ro
|
|
- ${APP_DATA_DIR}/index.html:/usr/share/nginx/html/index.html:ro
|
|
# Het app-icoon, voor de kop van de pagina en het tabblad. Geen template,
|
|
# dus dit bestand komt alleen bij een installatie mee en niet bij een
|
|
# update; voor een plaatje dat vrijwel nooit wijzigt is dat goed genoeg.
|
|
# De pagina valt terug op een ingebouwd merkje als de mount er niet is.
|
|
- ${APP_DATA_DIR}/icon.png:/usr/share/nginx/html/icon.png:ro
|
|
# Het stream-blok, dus de TLS-poort zelf. Het staat los van nginx.conf
|
|
# omdat nginx niet start met een 'listen ssl' zonder certificaat, en het
|
|
# command-blok hieronder zet het pas in /var/lib/gate/tls/ zodra de agent
|
|
# een certificaat gekozen heeft. Tot die tijd draait alleen de pagina.
|
|
- ${APP_DATA_DIR}/stream.conf:/etc/nginx/stream.conf:ro
|
|
# Dezelfde gedeelde toestand als de agent. nginx leest hier cert.conf en
|
|
# status.json, en schrijft de sessielog.
|
|
- ${APP_DATA_DIR}/data/runtime:/var/lib/gate
|
|
# De certificaten zelf moeten ook hier gemount zijn: de agent bepaalt
|
|
# welk pad in cert.conf komt, maar nginx moet het bestand kunnen openen.
|
|
- ${UMBREL_ROOT}/app-data/zoraxy/data/config/conf/certs:/certs/zoraxy:ro
|
|
- ${APP_DATA_DIR}/data/certs:/certs/own:ro
|
|
command:
|
|
- /bin/sh
|
|
- -c
|
|
- |
|
|
set -eu
|
|
mkdir -p /var/lib/gate
|
|
|
|
# Het log_format van de stream-sessies wordt hier geschreven en niet in
|
|
# nginx.conf.template. Een log_format bestaat uit nginx-variabelen met
|
|
# een dollarteken, en de template-invulling van umbreld zou die
|
|
# stilzwijgend leegmaken. In dit blok is een dollarteken als $$ te
|
|
# ontsnappen, dus hier kan het wel.
|
|
#
|
|
# Let op wat er NIET in staat: geen client-adres en geen bronpoort. Dat
|
|
# is precies het soort gegeven dat deze app van het netwerk af houdt, en
|
|
# om te zien dat het werkt is het niet nodig.
|
|
cat > /var/lib/gate/stream-log.conf <<'CONF'
|
|
log_format gate '$$time_iso8601 $$status $$bytes_received $$bytes_sent $$session_time';
|
|
access_log /var/lib/gate/stream.log gate;
|
|
CONF
|
|
|
|
# De TLS-poort aan of uit zetten, naar de toestand van cert.conf.
|
|
#
|
|
# Hier zat tot 0.0.3 een lus die wachtte tot de agent een certificaat
|
|
# gekozen had, en dat was fout: nginx startte dan niet, dus de pagina
|
|
# kwam niet omhoog, en de pagina is juist waar je dat certificaat kiest.
|
|
# Zonder Zoraxy, of met twee kandidaten, hing de app daarmee vast op een
|
|
# keuze die nergens te maken was.
|
|
#
|
|
# Nu start nginx altijd. Het stream-blok komt erbij zodra cert.conf er
|
|
# is, en verdwijnt weer als de agent zijn keuze intrekt. nginx.conf haalt
|
|
# deze map op met een jokerteken; die matcht dan niets en dat is geen
|
|
# fout.
|
|
mkdir -p /var/lib/gate/tls
|
|
#
|
|
# Deze functie eindigt altijd geslaagd, en dat is met opzet: het script
|
|
# draait onder 'set -e', dus een mislukte cp zou de aanroeper afbreken.
|
|
# In de lus hieronder is die aanroeper de wachtlus, en die mag om geen
|
|
# enkele reden stoppen.
|
|
sync_tls() {
|
|
if [ -f /var/lib/gate/cert.conf ]; then
|
|
# Kopieren en niet linken: nginx opent dit pad als de gebruiker
|
|
# nginx, en een symlink naar een read-only mount is nodeloos fragiel.
|
|
if cp /etc/nginx/stream.conf /var/lib/gate/tls/stream.conf; then
|
|
echo "Certificaat aanwezig, TLS luistert op 50022."
|
|
else
|
|
echo "stream.conf kon niet worden weggezet; TLS blijft uit."
|
|
fi
|
|
else
|
|
rm -f /var/lib/gate/tls/stream.conf
|
|
echo "Nog geen certificaat gekozen; TLS staat uit, de pagina werkt."
|
|
fi
|
|
}
|
|
sync_tls
|
|
|
|
# De verbindingsteller. nginx stream schrijft zijn logregel pas bij het
|
|
# sluiten van een sessie, en een wallet houdt zijn verbinding uren open;
|
|
# zonder deze teller lijkt een actieve wallet dus afwezig. Dat was de
|
|
# vraag van de gebruiker op 20-08-2026, en het open punt uit §4e van het
|
|
# plan Webinterface: hoe die toestand binnen de container af te lezen is.
|
|
#
|
|
# Antwoord: /proc/net/tcp. Dat geldt per netwerk-namespace, dus dit ziet
|
|
# alleen de sockets van deze container, en daarom staat deze teller hier
|
|
# en niet in de agent: die zit in een andere namespace en kan er niet bij.
|
|
# Kolom 2 is het lokale adres met de poort in hex, kolom 4 de toestand.
|
|
# C366 is 50022 en 01 is ESTABLISHED, dus de luisterende socket (0A) en de
|
|
# verbindingen naar de backend en naar de pagina vallen er buiten.
|
|
#
|
|
# Geteld wordt alleen het aantal. Geen adres en geen bronpoort, net als in
|
|
# het log_format hierboven.
|
|
count_sessions() {
|
|
cat /proc/net/tcp /proc/net/tcp6 2>/dev/null \
|
|
| awk '$$4 == "01" && $$2 ~ /:C366$$/ { n++ } END { print n+0 }'
|
|
}
|
|
|
|
# Meteen een 0 neerzetten, zodat de pagina "geen verbindingen" kan tonen
|
|
# in plaats van "onbekend" in het minuutje voor de eerste ronde.
|
|
count_sessions > /var/lib/gate/sessions
|
|
|
|
# De herlaadlus. De agent kan nginx niet zelf herladen: dat zou de
|
|
# Docker-socket vragen en die is er bewust uit. In plaats daarvan zet hij
|
|
# een vlagbestand neer en herlaadt nginx zichzelf. Een reload leest het
|
|
# nieuwe certificaat in zonder bestaande verbindingen te verbreken.
|
|
#
|
|
# Deze lus draait op de achtergrond en nginx wordt hieronder met exec het
|
|
# hoofdproces. Andersom gaat twee keer mis: de shell blijft dan PID 1 en
|
|
# geeft signalen niet door, en als nginx omvalt eindigt het script met
|
|
# exitcode 0, waardoor Docker een geslaagde afsluiting ziet en
|
|
# 'restart: on-failure' niet ingrijpt.
|
|
(
|
|
while true; do
|
|
sleep 10
|
|
|
|
# Eerst schrijven, dan mv: de agent leest dit bestand op zijn eigen
|
|
# moment en mag geen half bestand zien.
|
|
count_sessions > /var/lib/gate/sessions.tmp
|
|
mv /var/lib/gate/sessions.tmp /var/lib/gate/sessions
|
|
|
|
if [ -f /var/lib/gate/reload ]; then
|
|
echo "Certificaat gewijzigd, nginx herladen ..."
|
|
# Eerst wegzetten, dan herladen. Andersom zou een herlading die
|
|
# mislukt de vlag toch opruimen, en dan probeert hij het nooit meer.
|
|
mv /var/lib/gate/reload /var/lib/gate/reload.done
|
|
# Voor de herlading, niet erna: een reload leest de configuratie
|
|
# opnieuw, dus het stream-blok moet er dan al liggen.
|
|
sync_tls
|
|
# De herlading mag niet met 'set -e' meegaan. Een certificaat dat
|
|
# nginx niet aanneemt laat de reload falen, en dan zou deze lus
|
|
# verdwijnen: geen enkele latere wijziging wordt dan nog opgepikt,
|
|
# zonder dat er iets te zien is.
|
|
if ! nginx -s reload; then
|
|
echo "Herladen mislukt; nginx houdt de vorige configuratie."
|
|
fi
|
|
elif [ -f /var/lib/gate/cert.conf ] && [ ! -f /var/lib/gate/tls/stream.conf ]; then
|
|
# De vangnetregel. De agent zet de vlag bij elke wijziging, dus
|
|
# normaal komt hier niets langs; wel als de vlag verloren gaat of
|
|
# als cert.conf van een vorige installatie al klaarlag. Zonder deze
|
|
# tak zou TLS dan uit blijven staan tot de volgende wijziging.
|
|
echo "Certificaat gevonden zonder herlaadvlag, TLS aanzetten ..."
|
|
sync_tls
|
|
if ! nginx -s reload; then
|
|
echo "Herladen mislukt; nginx houdt de vorige configuratie."
|
|
fi
|
|
fi
|
|
done
|
|
) &
|
|
|
|
exec nginx -g 'daemon off;'
|