Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down