From e14ac3593f3c14bfd7966502b5a36230cdab2632 Mon Sep 17 00:00:00 2001 From: Matthew Demidoff Date: Sun, 6 Sep 2026 07:43:59 +0200 Subject: [PATCH] build(compose): read the tunnel token from the environment and expose cloudflared metrics The tunnel token was passed on cloudflared's command line, which put it in docker compose ps, docker top, and any crash report. cloudflared reads TUNNEL_TOKEN natively, so the compose service now sets that from the same CLOUDFLARED_TOKEN variable and drops --token from argv. --metrics 0.0.0.0:2000 serves /ready and /metrics on the compose network only (exposed, not published). The image is distroless, so readiness cannot be a container healthcheck; the worker will probe it in a later change. --- docker-compose.yml | 13 +++++++++++-- docs/deployment.md | 9 +++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 6611cd9..a757656 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -146,12 +146,21 @@ services: cloudflared: image: cloudflare/cloudflared:2026.6.0 restart: unless-stopped + # The token arrives via TUNNEL_TOKEN (which cloudflared reads natively) + # rather than argv, so it no longer shows in `docker compose ps`, + # `docker top`, or crash reports. --metrics serves /ready and /metrics on + # the compose network only; the image is distroless (no shell), so tunnel + # readiness is probed from another container, not by a healthcheck here. command: - tunnel - --no-autoupdate + - --metrics + - 0.0.0.0:2000 - run - - --token - - ${CLOUDFLARED_TOKEN:?set CLOUDFLARED_TOKEN} + environment: + TUNNEL_TOKEN: ${CLOUDFLARED_TOKEN:?set CLOUDFLARED_TOKEN} + expose: + - "2000" depends_on: app: condition: service_healthy diff --git a/docs/deployment.md b/docs/deployment.md index f81bf36..a66d0c7 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -27,6 +27,15 @@ the Compose network: Service: http://app:3000 ``` +The connector reads its token from the `TUNNEL_TOKEN` environment variable +(Compose maps `CLOUDFLARED_TOKEN` to it), so the token never appears in +`docker compose ps` or `docker top`. It also serves its metrics endpoint at +`http://cloudflared:2000` inside the Compose network: `/ready` returns 200 +only while at least one connection to the Cloudflare edge is registered, and +`/metrics` is Prometheus text. Neither is published on a host port. The image +is distroless, so there is no in-container healthcheck; readiness is checked +from another container. + ## Database and migrations The schema is loaded from `db/schema.sql` on first Postgres startup. Existing