Overview

Centralized cloudflared tunnel running in-cluster in the ingress namespace, replacing the per-app tunnel pattern. Tunnel name: cirrus. Authenticates via a locally-generated credentials.json (locally-managed tunnel), not a dashboard-issued token.

Architecture

config.yml (base, no routes yet)

tunnel: <TUNNEL_ID>
credentials-file: /etc/cloudflared/creds/credentials.json
protocol: http2

ingress:
  - service: http_status:404

Adding a route means inserting a hostname rule above the catch-all, e.g.:

ingress:
  - hostname: health.edisonwang.dev
    service: http://yyc-pc-health-ping.apps.svc.cluster.local:8000
  - service: http_status:404

DNS for each hostname is created via cloudflared tunnel route dns homelab-v2 <hostname> (auto-creates the CNAME to <TUNNEL-ID>.cfargotunnel.com).

Updating config.yml

kubectl create configmap cloudflared-config --from-file=config.yml -n ingress -o yaml --dry-run=client | kubectl apply -f -
kubectl rollout restart deployment cloudflared -n ingress

The restart is required — a mounted ConfigMap eventually syncs to the pod filesystem on its own, but cloudflared doesn't reliably watch the file for live changes, so a running pod can keep serving stale rules without it.

Known Issues

QUIC (UDP 7844) is blocked, forced to HTTP2 as permanent workaround

QUIC connectivity to the Cloudflare edge fails from both nodes (Failed to dial a quic connection: timeout: no recent network activity), while TCP/HTTP2 connectivity passes cleanly. This is consistent with a known WSL2 mirrored-networking-mode limitation, several Windows/WSL GitHub issues describe Windows periodically dropping outbound UDP for sustained/streaming flows (HTTP3/QUIC/WebTransport) specifically in mirrored mode, with no confirmed fix short of a reboot.