Skip to main content

Prod Cloudflare tunnel routing

info

This runbook uses the cloudflare and games/blaster repos together. It configures the Cloudflare tunnel for blaster.muppit.au, defines Origin CA resources in Kubernetes, and shows how to restart cloudflared without surprises.

Blaster GitOps series

  1. Blaster GitOps summary
  2. Blaster repo and branches
  3. Dockerfile & GitLab CI
  4. Clerk authentication & user setup
  5. Google OAuth for Clerk
  6. Blaster prep for automation
  7. Dev app k8s manifests
  8. Dev flux sources & Kustomizations
  9. Dev image automation
  10. Dev SOPS & age
  11. Dev verification & troubleshooting
  12. Dev full runbook
  13. Prod overview
  14. Prod app k8s manifests and deployment
  15. Prod Flux GitOps and image automation
  16. Prod Cloudflare, Origin CA and tunnel routing - you are here
  17. Prod full runbook
  18. Post development branches

1. Cloudflare repo changes

1.1 Pull latest

cd ~/Projects/cloudflare 
git pull
Already up to date.

1.2 Update cloudflared ConfigMap

---
# k8s/prod/40-configmap-cloudflared.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cloudflared
namespace: cloudflare
data:
config.yaml: |
tunnel: 3183eb59-d124-483f-90a1-3409e41b1d69
credentials-file: /etc/cloudflared/creds/credentials.json
metrics: 0.0.0.0:2000

ingress:
# (optional) Block WP admin to public
- hostname: muppit.au
path: ^/(wp-login\.php|wp-admin(?:/.*)?$)
service: http_status:403

# Send to ingress-nginx over TLS and verify with Origin CA
- hostname: muppit.au
service: https://ingress-nginx-controller.ingress-nginx.svc.cluster.local:443
originRequest:
originServerName: muppit.au
caPool: /etc/cloudflared/certs/origin_ca.pem

- hostname: blaster.muppit.au
service: https://ingress-nginx-controller.ingress-nginx.svc.cluster.local:443
originRequest:
originServerName: blaster.muppit.au
caPool: /etc/cloudflared/certs/origin_ca.pem

# Catch-all
- service: http_status:404

1.3 Commit and push

git add .
git commit -m "Added blaster to configmap"
[main 4d03596] Added blaster to configmap
1 file changed, 6 insertions(+)
git push
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 24 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 459 bytes | 459.00 KiB/s, done.
Total 5 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)
To https://gitlab.reids.net.au/muppit-apps/cloudflare.git
ff25bd4..4d03596 main -> main

1.4 Reconcile Origin CA issuer components

flux reconcile source git origin-ca-issuer-upstream -n flux-system && flux reconcile kustomization origin-ca-issuer-crds -n flux-system && flux reconcile kustomization origin-ca-issuer-rbac -n flux-system && flux reconcile kustomization origin-ca-issuer-controller -n flux-system
► annotating GitRepository origin-ca-issuer-upstream in flux-system namespace
✔ GitRepository annotated
◎ waiting for GitRepository reconciliation
✔ fetched revision v0.12.1@sha1:86d908eda6c91815557c04b7f3e871ca4f0a0cce
► annotating Kustomization origin-ca-issuer-crds in flux-system namespace
✔ Kustomization annotated
◎ waiting for Kustomization reconciliation
✔ applied revision v0.12.1@sha1:86d908eda6c91815557c04b7f3e871ca4f0a0cce
► annotating Kustomization origin-ca-issuer-rbac in flux-system namespace
✔ Kustomization annotated
◎ waiting for Kustomization reconciliation
✔ applied revision v0.12.1@sha1:86d908eda6c91815557c04b7f3e871ca4f0a0cce
► annotating Kustomization origin-ca-issuer-controller in flux-system namespace
✔ Kustomization annotated
◎ waiting for Kustomization reconciliation
✔ applied revision v0.12.1@sha1:86d908eda6c91815557c04b7f3e871ca4f0a0cce

2. Cloudflare DNS and tunnel

2.1 Initial reachability test (expected 404)

info

404 response is expected before blaster.muppit.au is added into the tunnel config.

curl -k https://blaster.muppit.au/ -I
HTTP/2 404 

2.2 Obtain tunnel ID

note

The existing tunnel ID is required for the DNS CNAME target in Cloudflare.

cloudflared tunnel list
You can obtain more detailed information for each tunnel with `cloudflared tunnel info <name/uuid>`
ID NAME CREATED CONNECTIONS

2.3 Cloudflare dashboard – DNS entry

  1. Log in to https://dash.cloudflare.com
  2. Add a new DNS entry:
    1. Type: CNAME
    2. Name: blaster
    3. Target: TUNNELID.cfargotunnel.com
    4. Proxy status: Proxied

3. Origin CA resources in Kubernetes

These resources live in the games/blaster repo under k8s/prod/ and are applied by Flux. They allow cloudflared to validate the origin using an Origin CA certificate.

3.1 Secret – Cloudflare API token copy

Reuse the same Cloudflare API token value as your cloudflare app repo; this copy must live in blaster so OriginIssuer can issue a cert in this namespace.

# k8s/prod/70-secret-cfapi-token.enc.yaml
apiVersion: v1
kind: Secret
metadata:
name: cfapi-token
namespace: blaster
type: Opaque
stringData:
key: PASTE_YOUR_API_TOKEN

3.2 OriginIssuer

# k8s/prod/80-originissuer.yaml
apiVersion: cert-manager.k8s.cloudflare.com/v1
kind: OriginIssuer
metadata:
name: cf-origin
namespace: blaster
spec:
requestType: OriginECC
auth:
tokenRef:
name: cfapi-token
key: key

3.3 Certificate for blaster.muppit.au

Issue an Origin CA certificate in the same namespace as your Ingress (blaster).

# k8s/prod/90-certificate-blaster.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: blaster-muppit-au-origin
namespace: blaster
spec:
secretName: blaster-muppit-au-tls
dnsNames:
- blaster.muppit.au
issuerRef:
group: cert-manager.k8s.cloudflare.com
kind: OriginIssuer
name: cf-origin

4. Restarting cloudflared after config change

4.1 Why a restart is required

  • The ConfigMap was changed in Git.
  • Flux reconciled and updated the ConfigMap object in the cluster.
  • The cloudflared Pod keeps running with the old config in memory.
  • Kubernetes does not automatically restart Pods when only a ConfigMap changes.
  • cloudflared does not re-read its config unless restarted (or run with a special watch mode).

Result:

  • Flux has synced Git → cluster.
  • The Deployment spec did not change.
  • No new ReplicaSet is created – the old Pod keeps the old config until you roll it.

4.2 Rollout restart

Manual restart:

kubectl -n cloudflare rollout restart deploy/cloudflared
kubectl -n cloudflare rollout status deploy/cloudflared
deployment.apps/cloudflared restarted
Waiting for deployment "cloudflared" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "cloudflared" rollout to finish: 1 old replicas are pending termination...
deployment "cloudflared" successfully rolled out

5. Reachability test – success

curl -k https://blaster.muppit.au/ -I
HTTP/2 200 

6. Verification checklist

  • cloudflared ConfigMap in cluster matches Git.
  • DNS CNAME blaster<TUNNELID>.cfargotunnel.com is present and proxied.
  • Secret/cfapi-token present in blaster namespace and encrypted in Git.
  • OriginIssuer/cf-origin and Certificate/blaster-muppit-au-origin are Ready=True.
  • blaster-muppit-au-tls Secret present and referenced by blaster-ingress.
  • curl -k https://blaster.muppit.au/ -I returns HTTP/2 200.