Cloudflare
Two Cloudflare products are in use: Tunnel (traffic routing) and Access (identity/auth perimeter).
Cloudflare Tunnel
The cloudflared container runs a persistent QUIC tunnel to the Cloudflare edge. It routes traffic from web.level147.net to http://level147-net:3000 via Docker’s proxy-net network.
The tunnel config maps the public hostname web.level147.net → origin service http://level147-net:3000.
Dashboard widget: reads metrics from CLOUDFLARED_METRICS_URL (set in .env).
Cloudflare Access
Cloudflare Access acts as the network perimeter — all requests to web.level147.net must pass identity verification before reaching the app. Authentik OIDC is the identity provider.
Docs site access
docs.level147.net is deployed to Cloudflare Pages and also protected by a separate Cloudflare Access application. The pages.dev preview domain is disabled to prevent Access bypass.
See Docs Site for the full deployment setup.
Auth flow
Security is enforced at two independent layers:
- Cloudflare Access — network perimeter. Blocks all unauthenticated requests before they reach the app. Enforces Cloudflare identity policy at
web.level147.net. - NextAuth v5 + Authentik OIDC — application layer.
src/middleware.tsguards all/api/*routes (except/api/auth/*and/api/health) as the framework-level choke point. Each API route handler also callsrequireSession()(src/lib/require-session.ts) for defense-in-depth, ensuring new routes are protected by default even if middleware config changes.
The app does not rely solely on Cloudflare Access — both layers must pass independently.
Troubleshooting 522
| Symptom | Cause | Fix |
|---|---|---|
522 on web.level147.net | Access app scoped to wrong domain | Check Zero Trust → Applications → hostname |
| Container healthy but 522 | Tunnel ingress pointing to wrong origin | Check tunnel public hostname service URL = http://level147-net:3000 |
| Tunnel disconnected | cloudflared QUIC timeout | docker restart cloudflared |
Full incident diagnosis steps: Incident Response.
v0.1.0 · d0d7a20 · 2026-06-26