Cloudflare
Cloudflare Tunnel
Outbound-only Cloudflare Tunnel connecting the homelab to the public internet without opening any inbound firewall ports. Runs as cloudflared-deployment in the default namespace of the k3s cluster.
Stack
| Item | Value |
|---|---|
| Image | cloudflare/cloudflared:2026.10.0 |
| Namespace | default |
| Replicas | 1, pinned to node cm4-left (nodeSelector) |
| Resources | requests 20m/32Mi, limits 200m/128Mi |
| Reloader | reloader.stakater.com/auto: "true" — auto-restarts if the tunnel token Secret changes |
How it works
cloudflared makes an outbound QUIC/HTTP2 connection to Cloudflare’s edge network and authenticates with a tunnel token (TUNNEL_TOKEN, from Secret/tunnel-token, key token). There is no Service, Ingress, or PersistentVolumeClaim for this workload — it’s stateless and only ever originates connections, never accepts them directly.
Public hostname routing rules (which hostname maps to which internal target) are configured entirely in the Cloudflare Zero Trust dashboard, not in this repo. Matched requests are forwarded over the tunnel to internal targets — primarily Traefik’s websecure (:443) Service, which then routes by hostname to whichever app is being requested.
1
Client → Cloudflare Edge → Tunnel (outbound from pod) → cloudflared pod → Traefik :443 → target Service
Container detail
1
2
3
4
5
6
7
8
9
command:
- cloudflared
- tunnel
- --no-autoupdate
- --loglevel
- info
- --metrics
- 0.0.0.0:2000
- run
securityContext.sysctls:net.ipv4.ping_group_range=65532 65532— allows the container to send ICMP (ping/traceroute) to internal backends, sincecloudflareddoesn’t haveNET_ADMINby default.livenessProbe:GET /ready :2000,failureThreshold: 1,initialDelaySeconds: 10,periodSeconds: 10—cloudflared’s/readyendpoint only returns 200 once it has an active connection to Cloudflare’s edge, so a failed probe means the tunnel itself is down, not just the process.
Security note
The tunnel token is stored as plaintext stringData in tunnel-token.yaml in the source repo, same pattern as other secrets in this workspace — treat that repo’s contents as sensitive, not just the live cluster Secret.
Deploy
1
kubectl apply -f deployment.yaml -f tunnel-token.yaml