From 550f71d2abfc6dba3bd60a6c563a84e2741f5500 Mon Sep 17 00:00:00 2001 From: Felix Faerber Date: Thu, 20 Aug 2026 12:38:06 +0300 Subject: [PATCH] Publish stamp-monitor at bee.t4t-gateway.com The gateway's /bee page shows a summary of the node. This exposes the monitor behind it, which is where batch fullness, the bucket map, wallet and chequebook runway, and the ledger of every top-up made or refused actually live. Left unrouted originally on the reasoning that its UI can spend xBZZ. That was the wrong test. The protection is that the app fails CLOSED -- every /api/admin route demands an x-admin-token and returns 503 when ADMIN_TOKEN is unset -- not that the port was hard to reach. Relying on the latter is how the batch went unwatched long enough to take the gateway down; a dashboard nobody can open is a dashboard nobody reads. Bee itself stays unpublished. Reaching it through the monitor's passthrough still requires the admin token, which is the whole reason the monitor sits in front of it. Also bumps the image to pick up the fix that makes Settings caps bind manual spending, not just the poller. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01YLYiaPYror1vLKApYKrxTu --- hostinger/prod-stack.yaml | 23 +++++++++++++++++++++-- hostinger/readme.md | 27 ++++++++++++++------------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/hostinger/prod-stack.yaml b/hostinger/prod-stack.yaml index 87f675f..96c25e1 100644 --- a/hostinger/prod-stack.yaml +++ b/hostinger/prod-stack.yaml @@ -34,8 +34,8 @@ services: # Bee node that saw them knows how full a batch is. Sitting next to prod_bee # is what makes fullness, the bucket map and batch_full alerts possible. stamp-monitor: - image: ghcr.io/ffaerber/swarm-stamp-monitor@sha256:62cf97f72090879f8d470fc9f2a09ab60d1d3a29dd658dfe2cd3a313c2b23540 - networks: [internal] + image: ghcr.io/ffaerber/swarm-stamp-monitor@sha256:aebf7e471f41cfdf43f8b6bc8dcdba4d29bc277612a302f61b7ed805b243901c + networks: [internal, public] volumes: - stamp-monitor-data:/data env_file: @@ -72,6 +72,25 @@ services: limits: cpus: "0.30" memory: 256M + # Published at bee.t4t-gateway.com. The gateway's own /bee page shows a + # summary; this is the full view — batch fullness, the bucket map, wallet + # and chequebook runway, and the action ledger. + # + # Safe to publish because the app fails CLOSED, not because the network + # protects it: every /api/admin route requires an x-admin-token and + # returns 503 when ADMIN_TOKEN is unset, so a misconfigured deploy is a + # visible outage rather than an open door onto endpoints that buy postage. + # The Bee node itself stays unpublished — reaching it through here still + # needs that token, which is the point of putting the monitor in front. + labels: + - "traefik.enable=true" + - "traefik.docker.network=public" + - "traefik.constraint-label=public" + - "traefik.http.routers.stamp-monitor.rule=Host(`bee.t4t-gateway.com`)" + - "traefik.http.routers.stamp-monitor.entrypoints=websecure" + - "traefik.http.routers.stamp-monitor.tls.certresolver=le" + - "traefik.http.services.stamp-monitor.loadbalancer.server.port=3000" + - "traefik.http.routers.stamp-monitor.middlewares=redirect-to-https" frontend: image: ghcr.io/token-for-token/hosted-gateway-frontend:main diff --git a/hostinger/readme.md b/hostinger/readme.md index 010e1e1..90017c6 100644 --- a/hostinger/readme.md +++ b/hostinger/readme.md @@ -30,6 +30,7 @@ Point all of these at `195.35.25.26`: A t4t-gateway.com 195.35.25.26 A www.t4t-gateway.com 195.35.25.26 A api.t4t-gateway.com 195.35.25.26 +A bee.t4t-gateway.com 195.35.25.26 A dev.t4t-gateway.com 195.35.25.26 A traefik.t4t-gateway.com 195.35.25.26 A grafana.t4t-gateway.com 195.35.25.26 @@ -104,9 +105,19 @@ not on-chain** — postage stamps are off-chain signatures, so only a node that saw them knows how full a batch is. A batch can be fully funded and still refuse writes. -No Traefik route and no published port: it is on `internal` only, and its UI -can spend xBZZ. Note `internal` is **not attachable**, so `docker run --network -internal ...` is refused — query through a container that is already on it: +Published at **[bee.t4t-gateway.com](https://bee.t4t-gateway.com)**. The +gateway's own `/bee` page shows a summary; this is the full view — batch +fullness and the bucket map, wallet and chequebook runway, and the ledger of +every top-up it has made or refused. + +It is publishable because the app fails **closed**: every `/api/admin` route +requires an `x-admin-token` and returns 503 if `ADMIN_TOKEN` is unset, so a +misconfigured deploy is a visible outage rather than an open door onto +endpoints that spend xBZZ. The Bee node stays unpublished; reaching it through +the monitor's passthrough still requires that token. + +From the shell, note `internal` is **not attachable**, so `docker run --network +internal ...` is refused — query through a container already on it: ```bash docker service logs --tail 50 prod_stamp-monitor @@ -115,16 +126,6 @@ M=$(docker ps --filter name=prod_stamp-monitor -q | head -1) docker exec $M bun -e 'console.log(await (await fetch("http://bee:1633/stamps")).text())' ``` -For the dashboard, publish it only for as long as you are looking at it, and -tunnel rather than exposing the port — swarm ingress binds `0.0.0.0`, so a -published port is on the public internet: - -```bash -docker service update --publish-add published=8088,target=3000 prod_stamp-monitor -ssh -L 8088:127.0.0.1:8088 root@ # then http://127.0.0.1:8088 -docker service update --publish-rm published=8088,target=3000 prod_stamp-monitor -``` - The API authenticates with an **`x-admin-token`** header, not `Authorization: Bearer`. A wrong header is a 401; a missing `ADMIN_TOKEN` in the service is a 503 (`admin API disabled`) — it fails closed, because these routes buy postage.