Gate 0.1.0: eigen image, het command-blok is een script, de app-map is leeg
Plan Eigenimage, fase 1 tot en met 3. De vier templates verhuizen naar tools/electrum-gate/ zonder extensie; daarnaast Dockerfile (nginx:1.30-alpine plus python3), entrypoint.sh (het command-blok van de compose, zonder $$) en build.sh naar het voorbeeld van Evolu Relay. Een image voor beide containers, gebouwd op de Umbrel; open punt 2 en 3 daarmee beslist. Inhoudelijk anders dan alleen verplaatst: het log_format staat in stream.conf zelf, het backend-adres komt via twee plaatshouders zonder dollarteken uit de omgeving (ook in de server-service), en de pagina haalt versie en adres uit status.json via GATE_APP_VERSION. Tests mee verhuisd en uitgebreid: entrypoint.sh en Dockerfile in plaats van het command-blok, en de tag in de compose gelijk aan VERSION in build.sh voor elke eigen image. Mutatie-getest met drie ingrepen. Nog niet gebouwd: er is hier geen Docker. De tag staat ongepind tot de eerste push; dat is fase 4 en die is van de gebruiker. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
7b3804df89
commit
973b24a23f
@@ -0,0 +1,54 @@
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# De image voor de app whatsnext-electrum-gate.
|
||||
#
|
||||
# Eén image voor twee containers. De compose start hem twee keer: als `server`
|
||||
# met het standaardcommando (entrypoint.sh, dat nginx wordt) en als `agent` met
|
||||
# `python3 /app/agent.py`. Twee images was netter gescheiden geweest, maar het
|
||||
# verdubbelt het bouw- en pinwerk, en nginx plus python3 in één alpine is klein.
|
||||
# Beslist bij de start van het plan Eigenimage, OPEN.md punt 2.
|
||||
#
|
||||
# Tot 0.0.29 stonden deze bestanden als *.template in de app-map en draaiden ze
|
||||
# op python:3-alpine en nginx:alpine. Wat dat kostte staat in het plan
|
||||
# Eigenimage, PLAN.md §3; het kortste antwoord: het command-blok van de compose
|
||||
# was ruim honderd regels shell in een YAML-string met verdubbelde dollartekens,
|
||||
# en dat is nu een gewoon script.
|
||||
#
|
||||
# De bouwcontext is de REPO-ROOT, niet deze map. Dat is omdat icon.png in de
|
||||
# app-map blijft staan (het manifest wijst ernaar voor de tegel in de winkel) en
|
||||
# de pagina hem óók nodig heeft; kopiëren uit de app-map voorkomt een tweede
|
||||
# exemplaar dat stil achterloopt. build.sh geeft die context mee.
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
# nginx en niet python als basis: de officiële nginx-image heeft de stream-module
|
||||
# ingebouwd, en op alpine's eigen nginx-pakket is dat een los pakket. De app draaide
|
||||
# al op nginx:alpine, dus dit houdt nginx precies zoals hij was. De tag is de
|
||||
# stable-reeks (even tweede cijfer); zie Docs/Referenties/Images-pinnen.md.
|
||||
FROM nginx:1.30-alpine
|
||||
|
||||
# De agent gebruikt alleen de standaardbibliotheek, inclusief ssl; dat zit in het
|
||||
# python3-pakket van alpine.
|
||||
RUN apk add --no-cache python3
|
||||
|
||||
COPY tools/electrum-gate/nginx.conf /etc/nginx/nginx.conf
|
||||
# Met .in erachter, want dit is nog niet de configuratie die nginx leest: het
|
||||
# backend-adres komt uit de omgeving en entrypoint.sh vult het bij het starten in.
|
||||
COPY tools/electrum-gate/stream.conf /etc/nginx/stream.conf.in
|
||||
COPY tools/electrum-gate/index.html /usr/share/nginx/html/index.html
|
||||
COPY whatsnext-electrum-gate/icon.png /usr/share/nginx/html/icon.png
|
||||
COPY tools/electrum-gate/agent.py /app/agent.py
|
||||
COPY tools/electrum-gate/entrypoint.sh /entrypoint.sh
|
||||
|
||||
# De uitvoerbit hier zetten en niet vertrouwen op wat git meegeeft: de repo wordt
|
||||
# ook op Windows bewerkt en daar bestaat die bit niet.
|
||||
RUN chmod 0755 /entrypoint.sh
|
||||
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
EXPOSE 80 50022
|
||||
|
||||
# De nginx-image heeft een eigen entrypoint dat scripts uit /docker-entrypoint.d
|
||||
# draait. Die doen hier niets nuttigs (envsubst op een templates-map die leeg is)
|
||||
# en één ervan zou, als hij ooit wél iets deed, precies de fout maken waar dit
|
||||
# project al een dag aan kwijt was. Weg ermee: het commando is het commando.
|
||||
ENTRYPOINT []
|
||||
CMD ["/entrypoint.sh"]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,111 @@
|
||||
#!/bin/sh
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# Bouwt de image voor de app whatsnext-electrum-gate.
|
||||
#
|
||||
# Eén image voor de twee containers van de app: nginx met de pagina en het
|
||||
# stream-blok, en python3 met de agent. Wat erin gaat staat in de Dockerfile
|
||||
# hiernaast; de bestanden zelf staan in deze map, behalve icon.png, dat in de
|
||||
# app-map blijft omdat het manifest ernaar wijst.
|
||||
#
|
||||
# Waarom dit NIET in de app-map staat: umbreld kopieert de hele app-map naar het
|
||||
# apparaat, en bij een update wordt alleen een whitelist ververst waar een
|
||||
# Dockerfile niet in zit. Bouwen tijdens het starten van de app zou de installatie
|
||||
# bovendien minuten laten hangen. Het recept hoort dus in de repo en het resultaat
|
||||
# in een register; de app verwijst alleen naar de tag.
|
||||
#
|
||||
# Draaien: sh tools/electrum-gate/build.sh
|
||||
# Vereist: docker op de machine waar je bouwt. Op de Umbrel is dat met sudo.
|
||||
#
|
||||
# Multi-arch: PLATFORMS="linux/amd64,linux/arm64" sh tools/electrum-gate/build.sh
|
||||
# Dat vraagt buildx met QEMU en duwt meteen naar het register, want een
|
||||
# multi-arch-manifest bestaat niet lokaal. Nog nooit geprobeerd; zie het plan
|
||||
# Eigenimage, PLAN.md §4. Zonder PLATFORMS bouwt dit één architectuur, die van
|
||||
# de machine waarop je staat, en dat is voor eigen gebruik op een amd64-Umbrel
|
||||
# genoeg.
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
set -eu
|
||||
|
||||
# ── De pin ────────────────────────────────────────────────────────────────────
|
||||
# Dit is het etiket op de IMAGE. Verhoog het als de image verandert, dus als er
|
||||
# iets in deze map of in icon.png wijzigt, en zet dan dezelfde waarde achter
|
||||
# `image:` in de compose (twee keer: agent en server delen hem).
|
||||
#
|
||||
# `version` in umbrel-app.yml is een ander nummer en mag hierop vooruitlopen: dat
|
||||
# moet bij élke wijziging aan de app omhoog, ook als alleen de compose verandert,
|
||||
# want anders rolt umbrelOS hem niet uit. Dat heeft hier een keer een dag gekost.
|
||||
# Sinds de eigen image raakt vrijwel elke wijziging de image, dus ze lopen
|
||||
# meestal gelijk; de regel blijft: verhoog je VERSION, dan ook het manifest.
|
||||
VERSION="0.1.0"
|
||||
|
||||
# Het register staat er expres in en dit is geen smaakkwestie: umbreld haalt élke
|
||||
# image op via de Docker Engine API, dus een tag die alleen lokaal bestaat is voor
|
||||
# hem onbereikbaar en de installatie faalt met "pull access denied". Dat is op
|
||||
# 25-08-2026 bij Evolu Relay op het apparaat vastgesteld.
|
||||
IMAGE="sc.kamenier-hamer.nl/sysop/electrum-gate:${VERSION}"
|
||||
|
||||
RECEPT="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
||||
# De bouwcontext is de repo-root, want icon.png komt uit de app-map. Zie de kop
|
||||
# van de Dockerfile.
|
||||
REPO="$(CDPATH= cd -- "${RECEPT}/../.." && pwd)"
|
||||
|
||||
# ── Controles vooraf ──────────────────────────────────────────────────────────
|
||||
# Beter hier hard falen dan een image bouwen die iets anders bevat dan je denkt.
|
||||
|
||||
for bestand in Dockerfile entrypoint.sh agent.py nginx.conf stream.conf index.html; do
|
||||
if [ ! -f "${RECEPT}/${bestand}" ]; then
|
||||
echo "FOUT: ${bestand} ontbreekt in ${RECEPT}" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -f "${REPO}/whatsnext-electrum-gate/icon.png" ]; then
|
||||
echo "FOUT: whatsnext-electrum-gate/icon.png ontbreekt in ${REPO}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Een accolade-variabele hoort hier nergens meer in: deze bestanden gaan niet
|
||||
# meer door envsubst, dus wat er staat is wat er draait. Staat er tóch een, dan
|
||||
# is dat een restant van de template-tijd en zou hij letterlijk in de pagina of
|
||||
# de configuratie terechtkomen.
|
||||
if grep -l '\${' "${RECEPT}/nginx.conf" "${RECEPT}/stream.conf" "${RECEPT}/index.html" 2>/dev/null; then
|
||||
echo "FOUT: de bestanden hierboven bevatten nog een \${...}; die wordt niet meer ingevuld." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── Bouwen ────────────────────────────────────────────────────────────────────
|
||||
|
||||
PLATFORMS="${PLATFORMS:-}"
|
||||
|
||||
if [ -n "$PLATFORMS" ]; then
|
||||
echo "Bouwen als ${IMAGE} voor ${PLATFORMS}, en meteen duwen"
|
||||
docker buildx build --platform "$PLATFORMS" --tag "$IMAGE" --push \
|
||||
--file "${RECEPT}/Dockerfile" "$REPO"
|
||||
echo
|
||||
echo "Geduwd. De index-digest:"
|
||||
docker buildx imagetools inspect "$IMAGE" | head -3
|
||||
else
|
||||
echo "Bouwen als ${IMAGE}"
|
||||
docker build --tag "$IMAGE" --file "${RECEPT}/Dockerfile" "$REPO"
|
||||
echo
|
||||
echo "Klaar:"
|
||||
docker image inspect --format '{{.RepoTags}} {{.Id}}' "$IMAGE"
|
||||
echo
|
||||
echo "Bouwen is niet genoeg: de app verwijst naar het register, want umbreld kan"
|
||||
echo "niet bij een image die alleen lokaal staat. Nog te doen:"
|
||||
echo
|
||||
echo " docker login sc.kamenier-hamer.nl"
|
||||
echo " docker push ${IMAGE}"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Zet daarna de digest uit de push-uitvoer achter de tag in"
|
||||
echo "whatsnext-electrum-gate/docker-compose.yml (twee keer, agent en server), en"
|
||||
echo "zet \`version\` in het manifest op ${VERSION}. Zonder die verhoging rolt"
|
||||
echo "umbrelOS het niet uit."
|
||||
echo
|
||||
echo "Controleer dat het anoniem te halen is, want umbreld krijgt geen"
|
||||
echo "inloggegevens mee. Log uit in dezelfde context waarin je inlogde, anders"
|
||||
echo "meet je je eigen sessie:"
|
||||
echo
|
||||
echo " docker logout sc.kamenier-hamer.nl && docker pull ${IMAGE}"
|
||||
@@ -0,0 +1,141 @@
|
||||
#!/bin/sh
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# Het startscript van de server-container van Electrum Gate.
|
||||
#
|
||||
# Tot 0.0.29 stond dit als inline command-blok in docker-compose.yml, omdat de
|
||||
# compose in de update-whitelist van umbreld staat en een los script niet. Dat
|
||||
# betekende shell in een YAML-string, met elk dollarteken verdubbeld omdat
|
||||
# umbreld anders elke ${...} leegmaakt. Sinds de eigen image is het een gewoon
|
||||
# bestand; wat het doet is niet veranderd.
|
||||
#
|
||||
# Drie dingen die hier gebeuren en waarom ze hier gebeuren en niet in de agent:
|
||||
#
|
||||
# 1. de TLS-poort aan- of uitzetten naar de toestand van cert.conf. nginx weigert
|
||||
# te starten met een 'listen ssl' zonder certificaat, en de pagina waarop je
|
||||
# dat certificaat kiest moet juist altijd omhoog komen;
|
||||
# 2. de open verbindingen tellen. Dat kan alleen in deze netwerk-namespace;
|
||||
# 3. nginx herladen als de agent een vlag neerzet. De agent kan dat niet zelf,
|
||||
# want dat zou de Docker-socket vragen en die is er bewust uit.
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
set -eu
|
||||
|
||||
STATE=/var/lib/gate
|
||||
mkdir -p "$STATE" "$STATE/tls"
|
||||
|
||||
# ── Het stream-blok invullen ──────────────────────────────────────────────────
|
||||
# Het backend-adres komt uit de omgeving, dezelfde twee variabelen die de agent
|
||||
# krijgt. Tot 0.0.29 vulde umbreld ze in via stream.conf.template; nu de
|
||||
# configuratie in de image zit, gebeurt dat hier. nginx kan in een proxy_pass van
|
||||
# het stream-blok zelf geen omgevingsvariabele lezen.
|
||||
#
|
||||
# Twee plaatshouders zonder dollarteken, zodat het bestand zelf nooit door een
|
||||
# envsubst-stap beschadigd kan worden, ook niet als iemand het ooit weer als
|
||||
# template in de app-map zet.
|
||||
if [ -n "${GATE_ELECTRUM_HOST:-}" ] && [ -n "${GATE_ELECTRUM_PORT:-}" ]; then
|
||||
sed -e "s|__GATE_ELECTRUM_HOST__|${GATE_ELECTRUM_HOST}|g" \
|
||||
-e "s|__GATE_ELECTRUM_PORT__|${GATE_ELECTRUM_PORT}|g" \
|
||||
/etc/nginx/stream.conf.in > /etc/nginx/stream.conf
|
||||
else
|
||||
# Zonder backend is er niets om naar door te sturen. De pagina komt wel omhoog
|
||||
# en de agent meldt daar dat het adres ontbreekt; TLS blijft uit.
|
||||
rm -f /etc/nginx/stream.conf
|
||||
echo "GATE_ELECTRUM_HOST of GATE_ELECTRUM_PORT ontbreekt; TLS blijft uit, de pagina werkt."
|
||||
fi
|
||||
|
||||
# ── De TLS-poort aan of uit ───────────────────────────────────────────────────
|
||||
# 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.
|
||||
#
|
||||
# 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 de map tls/ op
|
||||
# met een jokerteken; die matcht dan niets en dat is geen fout.
|
||||
#
|
||||
# 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 "$STATE/cert.conf" ] && [ -f /etc/nginx/stream.conf ]; then
|
||||
# Kopiëren en niet linken: nginx opent dit pad als de gebruiker nginx, en een
|
||||
# symlink is hier nodeloos fragiel.
|
||||
if cp /etc/nginx/stream.conf "$STATE/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 "$STATE/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.
|
||||
#
|
||||
# /proc/net/tcp geldt per netwerk-namespace, dus dit ziet alleen de sockets van
|
||||
# deze container, en daarom staat de 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 in stream.conf.
|
||||
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 > "$STATE/sessions"
|
||||
|
||||
# ── De herlaadlus ─────────────────────────────────────────────────────────────
|
||||
# Draait op de achtergrond; 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.
|
||||
reload_nginx() {
|
||||
# Een certificaat dat nginx niet aanneemt laat de reload falen. Dat mag niet
|
||||
# met 'set -e' meegaan, want dan verdwijnt de lus en wordt geen enkele latere
|
||||
# wijziging meer opgepikt, zonder dat er iets te zien is.
|
||||
if ! nginx -s reload; then
|
||||
echo "Herladen mislukt; nginx houdt de vorige configuratie."
|
||||
fi
|
||||
}
|
||||
|
||||
(
|
||||
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 > "$STATE/sessions.tmp"
|
||||
mv "$STATE/sessions.tmp" "$STATE/sessions"
|
||||
|
||||
if [ -f "$STATE/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 "$STATE/reload" "$STATE/reload.done"
|
||||
# Voor de herlading, niet erna: een reload leest de configuratie opnieuw,
|
||||
# dus het stream-blok moet er dan al liggen.
|
||||
sync_tls
|
||||
reload_nginx
|
||||
elif [ -f "$STATE/cert.conf" ] && [ ! -f "$STATE/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
|
||||
reload_nginx
|
||||
fi
|
||||
done
|
||||
) &
|
||||
|
||||
exec nginx -g 'daemon off;'
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
||||
# nginx-configuratie voor Electrum Gate.
|
||||
#
|
||||
# Dit bestand zit in de image (tools/electrum-gate/Dockerfile) als
|
||||
# /etc/nginx/nginx.conf. Tot 0.0.29 was het een *.template in de app-map die
|
||||
# umbreld bij elke start door envsubst haalde, en daarom mocht er toen geen
|
||||
# nginx-variabele met een dollarteken in staan. Die beperking is weg. Dat de
|
||||
# access_log voor http nog steeds uit staat is een keuze en geen restant: de
|
||||
# pagina hangt achter de app_proxy en wat die opvraagt is niet interessant.
|
||||
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
# ── De web-UI ────────────────────────────────────────────────────────────────
|
||||
# Wordt niet rechtstreeks gepubliceerd: umbrelOS zet er zijn eigen app_proxy
|
||||
# voor, en die verwijst naar poort 80 van deze container.
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
access_log off;
|
||||
sendfile on;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# status.json wordt door de agent in de gedeelde map geschreven, niet in
|
||||
# de webroot. Geen cache: de pagina vraagt hem juist op om te zien hoe
|
||||
# oud de gegevens zijn.
|
||||
location = /status.json {
|
||||
alias /var/lib/gate/status.json;
|
||||
add_header Cache-Control "no-store";
|
||||
}
|
||||
|
||||
# De API van de agent. Het enige pad waarlangs iets van buiten de
|
||||
# instellingen van de app raakt, en dat is de certificaatkeuze.
|
||||
#
|
||||
# Waarom dit te verantwoorden is op een app waarvan de kleinheid het punt
|
||||
# is: het pad hangt achter de app_proxy van umbrelOS, die er zijn eigen
|
||||
# inlog voor zet, de TLS-poort staat er los van, en de agent accepteert
|
||||
# alleen een certificaat-id die hij zelf in de gemounte mappen gevonden
|
||||
# heeft. Het ergste wat een geslaagde aanroep doet is een ander, ook
|
||||
# bestaand, certificaat kiezen.
|
||||
#
|
||||
# Geen proxy_set_header hier: de agent heeft ze niet nodig.
|
||||
#
|
||||
# De volledige containernaam en niet de servicenaam 'agent'. Dat stond er
|
||||
# tot 0.0.23 wel, en het werkte zolang deze app de enige was met een
|
||||
# service van die naam. Sinds Evolu Relay er is, is dat niet meer waar:
|
||||
# beide apps zitten op hetzelfde Docker-netwerk, allebei met een 'agent'
|
||||
# op poort 8000, en Docker verdeelt de naam dan over de twee. Op
|
||||
# 28-08-2026 gemeten op het apparaat: van tien verzoeken kwamen er vijf
|
||||
# bij de verkeerde app uit. De vorm <app-id>_<service>_1 is uniek per app;
|
||||
# het is dezelfde les die in de compose al stond over de naam 'server'.
|
||||
location /api/ {
|
||||
proxy_pass http://whatsnext-electrum-gate_agent_1:8000;
|
||||
client_max_body_size 1k;
|
||||
}
|
||||
|
||||
# Het uploaden van een certificaat, en het enige pad met een grotere
|
||||
# limiet: een sleutel plus keten haalt de 1k van hierboven ruim. Een
|
||||
# exacte match, dus deze regel wint van /api/ hierboven en de grotere
|
||||
# limiet geldt nergens anders. De agent kapt zelf ook af, op 96k; deze
|
||||
# limiet is de eerste zeef en niet de enige.
|
||||
location = /api/certificate/upload {
|
||||
proxy_pass http://whatsnext-electrum-gate_agent_1:8000;
|
||||
client_max_body_size 96k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ── De TLS-terminatie ────────────────────────────────────────────────────────
|
||||
# Die staat niet hier maar in stream.conf, en dat is geen ordening maar de
|
||||
# reparatie van een klem. nginx weigert te starten als een 'listen ... ssl' geen
|
||||
# certificaat heeft; stond het stream-blok hier, dan kwam met dat blok ook de
|
||||
# pagina hierboven niet omhoog zolang de agent geen certificaat gekozen had. En
|
||||
# de pagina is juist de plek waar die keuze gemaakt wordt.
|
||||
#
|
||||
# entrypoint.sh legt stream.conf in de map hieronder zodra cert.conf bestaat, en
|
||||
# haalt het weg als dat niet zo is. Een include met een jokerteken die nergens op
|
||||
# uitkomt is voor nginx geen fout, dus zonder certificaat start deze server
|
||||
# zonder poort 50022 en met een pagina die vertelt waarom.
|
||||
include /var/lib/gate/tls/*.conf;
|
||||
@@ -0,0 +1,65 @@
|
||||
# De TLS-terminatie van Electrum Gate, als los bestand, en dat is de hele truc.
|
||||
#
|
||||
# nginx weigert te starten als een 'listen ... ssl' geen certificaat heeft, en
|
||||
# welk certificaat dat wordt weet alleen de agent. Zolang dit blok in nginx.conf
|
||||
# stond, kwam de server dus niet omhoog voordat er een keuze lag, en daarmee ook
|
||||
# de web-UI niet: precies de pagina waarop die keuze gemaakt wordt. Een gebruiker
|
||||
# zonder Zoraxy, of met twee kandidaten, zag daardoor helemaal niets en had geen
|
||||
# enkele weg vooruit. Zo aangetroffen in 0.0.3.
|
||||
#
|
||||
# Nu staat het blok hier, en entrypoint.sh zet dit bestand pas in
|
||||
# /var/lib/gate/tls/ zodra de agent cert.conf geschreven heeft. nginx.conf haalt
|
||||
# die map op met een jokerteken, en een jokerteken dat niets matcht is voor nginx
|
||||
# geen fout. Geen certificaat betekent dus: geen stream-blok, geen poort 50022,
|
||||
# maar wel een werkende pagina die vertelt wat eraan mankeert.
|
||||
#
|
||||
# Dit bestand zit in de image als /etc/nginx/stream.conf.in. De twee plaatshouders
|
||||
# __GATE_ELECTRUM_HOST__ en __GATE_ELECTRUM_PORT__ vult entrypoint.sh bij het
|
||||
# starten in uit de omgeving; nginx kan in een proxy_pass van het stream-blok zelf
|
||||
# geen omgevingsvariabele lezen. Tot 0.0.29 was dit een *.template in de app-map
|
||||
# en deed umbreld die invulling, en daarom mocht er toen geen nginx-variabele met
|
||||
# een dollarteken in staan. Die beperking is weg: het log_format staat nu gewoon
|
||||
# hier en niet meer in een los bestand dat het command-blok wegschreef.
|
||||
|
||||
stream {
|
||||
# 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.
|
||||
log_format gate '$time_iso8601 $status $bytes_received $bytes_sent $session_time';
|
||||
access_log /var/lib/gate/stream.log gate;
|
||||
|
||||
server {
|
||||
# 50022 en niet 50002; de reden staat bij de ports-regel in
|
||||
# docker-compose.yml. Wijzig je dit, wijzig dan ook de hex-poort in de
|
||||
# verbindingsteller van entrypoint.sh.
|
||||
listen 50022 ssl;
|
||||
|
||||
# ssl_certificate en ssl_certificate_key, geschreven door de agent op
|
||||
# grond van wat er in de certificaatmappen staat en wat de gebruiker op
|
||||
# het dashboard gekozen heeft. Daarom staat er hier geen domeinnaam meer
|
||||
# in dit bestand. Dat dit bestand bestaat betekent dat cert.conf er is:
|
||||
# entrypoint.sh zet het er pas dan neer.
|
||||
#
|
||||
# nginx wil de VOLLEDIGE keten in ssl_certificate, dus het bestand van
|
||||
# Zoraxy kan er ongewijzigd in. Splitsen in een servercertificaat en een
|
||||
# CA-deel, zoals de oude stunnel-opzet deed, is hier juist fout.
|
||||
include /var/lib/gate/cert.conf;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
|
||||
# Een Electrum-wallet houdt een langlopende verbinding open die het
|
||||
# grootste deel van de tijd stil is. De standaardwaarde van
|
||||
# proxy_timeout is tien minuten, en die verbreekt zo'n verbinding dus
|
||||
# zonder aanleiding; de wallet merkt dat pas als hij iets wil en meldt
|
||||
# dan dat er geen data is. stunnel hanteerde hier twaalf uur, en dat
|
||||
# verschil is bij de overstap naar nginx over het hoofd gezien.
|
||||
proxy_timeout 12h;
|
||||
proxy_connect_timeout 10s;
|
||||
|
||||
# Houdt de verbinding naar de backend levend en laat een verbroken
|
||||
# verbinding sneller opvallen dan pas bij het volgende verzoek.
|
||||
proxy_socket_keepalive on;
|
||||
|
||||
proxy_pass __GATE_ELECTRUM_HOST__:__GATE_ELECTRUM_PORT__;
|
||||
}
|
||||
}
|
||||
@@ -10,11 +10,13 @@
|
||||
//
|
||||
// ── Waarom dit bestaat ───────────────────────────────────────────────────────
|
||||
//
|
||||
// Een `index.html.template` is niet te openen. Twee dingen staan in de weg, en ze
|
||||
// Een statuspagina is niet zomaar te openen. Twee dingen staan in de weg, en ze
|
||||
// zijn allebei fundamenteel en niet op te lossen door er anders naar te kijken:
|
||||
//
|
||||
// 1. er staan accolade-variabelen in die umbreld invult. Onopgelost staat er
|
||||
// letterlijk "v${APP_VERSION}" in de kop;
|
||||
// 1. in een `index.html.template` staan accolade-variabelen die umbreld invult.
|
||||
// Onopgelost staat er letterlijk "v${APP_VERSION}" in de kop. Een pagina die
|
||||
// in een eigen image zit heeft dit niet meer, maar haalt de versie dan uit
|
||||
// status.json, dus zonder agent staat er niets;
|
||||
// 2. de pagina haalt al zijn gegevens bij een agent die alleen in de app bestaat.
|
||||
// Zonder die agent zie je één foutmelding en verder een pagina vol "unknown":
|
||||
// geen lijsten, geen teller, geen knoppen.
|
||||
@@ -44,10 +46,18 @@ const REPO = join(HIER, '..');
|
||||
const UIT = join(REPO, 'voorbeeld');
|
||||
|
||||
const app = process.argv[2] || 'whatsnext-evolu-relay';
|
||||
const bron = join(REPO, app, 'index.html.template');
|
||||
|
||||
// De pagina staat op een van twee plekken: als *.template in de app-map, of als
|
||||
// gewoon bestand in het bouwrecept onder tools/ als hij in een eigen image zit.
|
||||
// Electrum Gate is sinds 0.1.0 het tweede geval. Alleen de eerste gaat door
|
||||
// envsubst; voor de tweede is de invulling hieronder een lege stap.
|
||||
const template = join(REPO, app, 'index.html.template');
|
||||
const kort = app.includes('-') ? app.slice(app.indexOf('-') + 1) : app;
|
||||
const inImage = join(REPO, 'tools', kort, 'index.html');
|
||||
const bron = existsSync(template) ? template : inImage;
|
||||
|
||||
if (!existsSync(bron)) {
|
||||
console.error(`FOUT: ${bron} bestaat niet`);
|
||||
console.error(`FOUT: geen pagina gevonden op ${template} of ${inImage}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user