Skip to content

Cloudflare Tunnel (cloudflared)

Secure, outbound-only tunnel between your Kubernetes cluster and Cloudflare’s global network. cloudflared connects to Cloudflare from inside the cluster — no open inbound ports, no public IP required. Traffic routing is managed in the Cloudflare dashboard via Public Hostnames. The default install uses a tokenless quick tunnel for demos and smoke tests; production managed tunnels explicitly disable quick tunnel mode and use an existing Secret or tunnel token with HA settings.

cloudflared replaces the Ingress controller for publicly exposed services

When using Cloudflare Tunnel, traffic routing is configured in the Cloudflare dashboard under Networks → Tunnels → Public Hostnames — not via Kubernetes Ingress resources. Adding a Kubernetes Ingress for the same service duplicates routing and is usually unnecessary. Services are referenced by their cluster-internal DNS (e.g. http://my-service.namespace.svc.cluster.local:80).

Key Features

  • Zero-trust networking — outbound-only connections, no inbound firewall rules needed
  • Tokenless default — quick tunnel mode installs without a Cloudflare token for demos and smoke tests
  • HA-ready production — 2+ replicas and PodDisruptionBudget can be enabled for managed tunnels
  • Dashboard-managed routing — Public Hostnames configured in the Cloudflare dashboard
  • Prometheus metrics/ready and /metrics endpoint on port 2000, enabled by default
  • ServiceMonitor — optional Prometheus Operator integration
  • Existing Secret support — bring your own Secret for the tunnel token
  • External Secrets Operator — optionally render an ExternalSecret for the tunnel token
  • Quick tunnel mode — ephemeral tunnel mode for demos and smoke tests
  • Dual-stack Service fields — optional ipFamilyPolicy and ipFamilies

Quick Start

The chart installs without values by running an ephemeral quick tunnel. For a managed production tunnel:

  1. Go to Cloudflare Zero Trust dashboardNetworks → Tunnels
  2. Create a new tunnel and copy the token
  3. Deploy this chart with the token
helm install cloudflared helmforge/cloudflared \
  --set tunnel.quickTunnel.enabled=false \
  --set tunnel.token='eyJhIjoiY2Y...'
  1. In the dashboard, add Public Hostnames mapping your domain to services inside the cluster (e.g. https://app.example.com → http://myapp.default.svc.cluster.local:80)

Installation

HTTPS repository:

helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install cloudflared helmforge/cloudflared -f values.yaml

OCI registry:

helm install cloudflared oci://ghcr.io/helmforgedev/helm/cloudflared -f values.yaml

Deployment Examples

# values.yaml — managed cloudflared with inline token (not recommended for production)
# Store the token in an existing Secret for production environments.
tunnel:
  quickTunnel:
    enabled: false
  token: 'eyJhIjoiY2Y...' # From Cloudflare dashboard

replicaCount: 2

pdb:
  enabled: true
  minAvailable: 1
# values.yaml — Production cloudflared with secret-backed token and Prometheus metrics
# Create the secret first: kubectl create secret generic cloudflare-tunnel --from-literal=token='eyJ...'
tunnel:
  quickTunnel:
    enabled: false
  existingSecret: cloudflare-tunnel
  existingSecretKey: token

replicaCount: 2

pdb:
  enabled: true
  minAvailable: 1

resources:
  requests:
    cpu: 50m
    memory: 64Mi
  limits:
    memory: 128Mi

metrics:
  enabled: true

serviceMonitor:
  enabled: true
  interval: 30s
  labels:
    prometheus: kube-prometheus
# values.yaml — External Secrets Operator generates the Kubernetes Secret
tunnel:
  quickTunnel:
    enabled: false
  existingSecret: cloudflared-tunnel-token
  existingSecretKey: token

externalSecrets:
  enabled: true
  secretStoreRef:
    name: platform-secrets
    kind: ClusterSecretStore
  data:
    - secretKey: token
      remoteRef:
        key: cloudflared/tunnel
        property: token
# values.yaml — ephemeral quick tunnel for demos and smoke tests only
tunnel:
  quickTunnel:
    enabled: true
    helloWorld: true

replicaCount: 1
pdb:
  enabled: false
# values.yaml — Single replica for dev or resource-constrained environments
tunnel:
  quickTunnel:
    enabled: false
  existingSecret: cloudflare-tunnel
  existingSecretKey: token

replicaCount: 1

pdb:
  enabled: false # PDB with minAvailable:1 would block all maintenance on 1-replica deployments

Configuration Reference

Core

Parameter Type Default Description
nameOverride string "" Override the chart name.
fullnameOverride string "" Override the full release name.
commonLabels object {} Extra labels added to all resources.

Image

Parameter Type Default Description
image.repository string docker.io/cloudflare/cloudflared cloudflared container image.
image.tag string "2026.5.2" Image tag.
image.pullPolicy string IfNotPresent Image pull policy.
imagePullSecrets array [] Pull secrets for private registries.

Tunnel

Parameter Type Default Description
tunnel.token string "" Tunnel token from the Cloudflare dashboard. Prefer existingSecret in production.
tunnel.existingSecret string "" Existing Kubernetes Secret containing the tunnel token.
tunnel.existingSecretKey string token Key inside the existing Secret for the token value.
tunnel.quickTunnel.enabled boolean true Run an ephemeral quick tunnel for demos and smoke tests. Set false for managed tunnels.
tunnel.quickTunnel.helloWorld boolean true Use cloudflared’s built-in hello-world origin in quick tunnel mode.
tunnel.quickTunnel.url string http://localhost:8080 Origin URL when quick tunnel mode does not use hello-world.
Do not store the tunnel token inline in values.yaml for production

Setting tunnel.token inline exposes the token in helm get values and Helm release history. Use tunnel.existingSecret with a pre-created Kubernetes Secret. The token grants full control over the tunnel and cannot be rotated without updating the Cloudflare dashboard.

cloudflared Options

Parameter Type Default Description
cloudflared.logLevel string info Log verbosity: info, debug, warn, error, or fatal.
cloudflared.noAutoupdate boolean true Disable in-process auto-update. Always true in containers.
cloudflared.metricsPort integer 2000 Port serving /ready and /metrics.
cloudflared.extraArgs array [] Extra command-line arguments appended to the cloudflared command.
cloudflared.extraEnv array [] Extra environment variables for the container.

Replicas and Availability

Parameter Type Default Description
replicaCount integer 1 Number of cloudflared replicas. Use 2 or more for production managed tunnels.
Do not use HPA with cloudflared

Horizontal Pod Autoscaling that scales down replicas terminates active tunnel connections immediately. Clients connected through those tunnels will experience dropped connections. Use a fixed replicaCount of 2 or more instead of autoscaling.

PodDisruptionBudget

Parameter Type Default Description
pdb.enabled boolean false Create a PodDisruptionBudget for cloudflared pods.
pdb.minAvailable integer 1 Minimum available replicas during voluntary cluster disruptions.

Service

Parameter Type Default Description
service.type string ClusterIP Kubernetes service type.
service.port integer 2000 Metrics service port.
service.annotations object {} Annotations for the Service.
service.ipFamilyPolicy string "" Optional Service IP family policy for dual-stack.
service.ipFamilies array [] Optional ordered Service IP families.

External Secrets

Parameter Type Default Description
externalSecrets.enabled boolean false Render an External Secrets Operator ExternalSecret.
externalSecrets.secretStoreRef.name string "" SecretStore or ClusterSecretStore name.
externalSecrets.secretStoreRef.kind string SecretStore Secret store kind.
externalSecrets.data array [] Data mappings used to populate the tunnel token Secret.

Metrics

Parameter Type Default Description
metrics.enabled boolean true Expose the metrics Service for /ready and /metrics.
serviceMonitor.enabled boolean false Create a Prometheus Operator ServiceMonitor.
serviceMonitor.interval string 30s Metrics scrape interval.
serviceMonitor.labels object {} Extra labels added to the ServiceMonitor.

Probes

Parameter Type Default Description
probes.startup.enabled boolean true Enable startup probe on /ready.
probes.startup.initialDelaySeconds integer 15 Startup probe initial delay.
probes.startup.periodSeconds integer 5 Startup probe period.
probes.startup.timeoutSeconds integer 3 Startup probe timeout.
probes.startup.failureThreshold integer 12 Startup probe failure threshold.
probes.liveness.enabled boolean true Enable liveness probe on /ready.
probes.liveness.initialDelaySeconds integer 0 Liveness probe initial delay.
probes.liveness.periodSeconds integer 15 Liveness probe period.
probes.liveness.timeoutSeconds integer 5 Liveness probe timeout.
probes.liveness.failureThreshold integer 3 Liveness probe failure threshold.
probes.readiness.enabled boolean true Enable readiness probe on /ready.
probes.readiness.initialDelaySeconds integer 0 Readiness probe initial delay.
probes.readiness.periodSeconds integer 10 Readiness probe period.
probes.readiness.timeoutSeconds integer 5 Readiness probe timeout.
probes.readiness.failureThreshold integer 3 Readiness probe failure threshold.

Resources and Security

Parameter Type Default Description
resources.requests.cpu string 50m Default CPU request.
resources.requests.memory string 64Mi Default memory request.
resources.limits.cpu string 250m Default CPU limit.
resources.limits.memory string 128Mi Default memory limit.
podSecurityContext object non-root seccomp defaults Pod-level security context.
securityContext object non-root read-only defaults Container-level security context.

Service Account

Parameter Type Default Description
serviceAccount.create boolean false Create a dedicated ServiceAccount.
serviceAccount.name string "" Override the ServiceAccount name.
serviceAccount.annotations object {} Annotations for the ServiceAccount.

Scheduling

Parameter Type Default Description
nodeSelector object {} Node selector for scheduling.
tolerations array [] Tolerations for scheduling.
affinity object {} Affinity rules.
topologySpreadConstraints array [] Topology spread constraints.
priorityClassName string "" PriorityClass for the pod.
terminationGracePeriodSeconds integer 30 Termination grace period.
podLabels object {} Extra labels for the pod.
podAnnotations object {} Extra annotations for the pod.

Extra

Parameter Type Default Description
extraVolumes array [] Extra volumes to attach to the pod.
extraVolumeMounts array [] Extra volume mounts for the container.
extraManifests array [] Extra Kubernetes manifests deployed alongside the chart.

More Information