Skip to content

Controller Options

This document describes all configuration options for the controller binary. For Helm chart values, see Helm Values.

Command Line Flags

Flag Environment Variable Default Description
--controller-name CF_CONTROLLER_NAME cf.k8s.lex.la/tunnel-controller Controller name matching GatewayClass spec.controllerName
--cluster-domain CF_CLUSTER_DOMAIN (auto-detect) Kubernetes cluster domain
--metrics-addr CF_METRICS_ADDR :8080 Metrics endpoint address
--health-addr CF_HEALTH_ADDR :8081 Health probe endpoint address
--log-level CF_LOG_LEVEL info Log level (debug, info, warn, error)
--log-format CF_LOG_FORMAT json Log format (json, text)
--leader-elect CF_LEADER_ELECT false Enable leader election for HA
--leader-election-namespace CF_LEADER_ELECTION_NAMESPACE Namespace for leader election lease
--leader-election-name CF_LEADER_ELECTION_NAME cloudflare-tunnel-gateway-controller-leader Leader election lease name
--proxy-endpoints CF_PROXY_ENDPOINTS Proxy config API endpoints for L7 proxy sync (required in v3)
--proxy-auth-token CF_PROXY_AUTH_TOKEN Bearer token for proxy config push authentication, as a direct value. For callers outside the chart only -- the chart always sets --proxy-auth-secret-ref instead, for both the bring-your-own and generated cases. Overridden by --proxy-auth-secret-ref when both are set
--proxy-auth-secret-ref CF_PROXY_AUTH_SECRET_REF Shared-proxy config-API auth-token Secret to resolve, in <namespace>/<name> form, and use for the controller's own push auth. Resolved directly via the API, not a pod-level secretKeyRef (which the controller creating its own dependency would deadlock on). The single mechanism the chart uses for both the bring-your-own and generated cases; combine with --proxy-auth-secret-generate
--proxy-auth-secret-key CF_PROXY_AUTH_SECRET_KEY auth-token Data key to read within the --proxy-auth-secret-ref Secret
--proxy-auth-secret-generate CF_PROXY_AUTH_SECRET_GENERATE false Allow creating the --proxy-auth-secret-ref Secret (with a random token) when it does not exist. false is the bring-your-own contract: the Secret must already exist. The chart sets this true only when proxy.authTokenSecretRef.name is empty
--proxy-token-secret CF_PROXY_TOKEN_SECRET Tunnel-token Secret to watch in <namespace>/<name> form; the controller rolls the proxy Deployment when the Secret data changes. Empty disables the watcher
--proxy-deployment-label CF_PROXY_DEPLOYMENT_LABEL app.kubernetes.io/component=proxy Label selector (key=value) identifying the proxy Deployment(s) to roll on tunnel-token change
--tunnel-protocol CF_TUNNEL_PROTOCOL auto Edge transport protocol (auto, http2, quic); used to warn when GRPCRoutes are present on an explicit quic tunnel
--tracing-enabled CF_TRACING_ENABLED false Enable OpenTelemetry distributed tracing
--tracing-endpoint CF_TRACING_ENDPOINT OTLP/gRPC collector endpoint (defers to OTEL_EXPORTER_OTLP_ENDPOINT when empty)
--tracing-sample-rate CF_TRACING_SAMPLE_RATE 1.0 Head-sampling probability in [0,1]
--proxy-image CF_PROXY_IMAGE Container image for per-Gateway rendered proxy Deployments (per-Gateway isolation). When BOTH this flag and the GatewayConfig.spec.image override are empty, rendering is skipped and the Gateway surfaces a Warning Event instead of a data plane. The Helm chart always sets it; manual installs should pass it (or set spec.image per GatewayConfig)
--hostname-ownership-enforce CF_HOSTNAME_OWNERSHIP_ENFORCE false Controller-side hostname-ownership layer: routes whose hostnames fall outside their namespace's allowed-suffix label are rejected (HostnameNotPermitted) and never programmed. Independent of the chart's ValidatingAdmissionPolicy — see Multi-Tenancy
--hostname-ownership-label-key CF_HOSTNAME_OWNERSHIP_LABEL_KEY cf.k8s.lex.la/hostname-suffix Namespace label carrying the tenant's allowed hostname suffix
--hostname-ownership-namespace-selector CF_HOSTNAME_OWNERSHIP_NAMESPACE_SELECTOR Label selector (kubectl syntax) scoping which namespaces are policed; empty polices every namespace (fail-closed)
--monitoring-namespace-selector CF_MONITORING_NAMESPACE_SELECTOR Label selector (kubectl syntax) for namespaces additionally allowed to reach a per-Gateway proxy's config-API/metrics port in the rendered NetworkPolicy; empty admits the controller namespace only — see Per-Gateway Isolation
--render-network-policy CF_RENDER_NETWORK_POLICY true Render the per-Gateway config-API NetworkPolicy. Wired from the chart's proxy.networkPolicy.enabled. Set false on strict CNIs where node-sourced kubelet probes are blocked by the policy's namespaceSelector ingress rule; a previously-rendered policy is then deleted

For full distributed-tracing setup, see Distributed Tracing.

Environment Variables

All flags can be set via environment variables with the CF_ prefix. Dashes in flag names are replaced with underscores.

Examples:

  • --controller-nameCF_CONTROLLER_NAME
  • --log-levelCF_LOG_LEVEL
  • --leader-electCF_LEADER_ELECT

Cluster Domain Auto-Detection

The controller automatically detects the Kubernetes cluster domain from /etc/resolv.conf search domains. If detection fails, it falls back to cluster.local.

To override auto-detection:

--cluster-domain=my-cluster.local

Or via environment variable:

CF_CLUSTER_DOMAIN=my-cluster.local

Leader Election

For high availability deployments with multiple controller replicas, enable leader election:

--leader-elect=true
--leader-election-namespace=cloudflare-tunnel-system

Only the leader processes events; other replicas remain on standby for automatic failover.

flowchart LR
    subgraph Replicas
        R1[Replica 1<br/>Leader]
        R2[Replica 2<br/>Standby]
        R3[Replica 3<br/>Standby]
    end

    LEASE[(Lease)]

    R1 -->|holds| LEASE
    R2 -.->|watches| LEASE
    R3 -.->|watches| LEASE

Logging

Log Levels

Level Description
debug Detailed debugging information
info Normal operational messages
warn Warning conditions
error Error conditions

Log Formats

Format Description
json Structured JSON logs (recommended for production)
text Human-readable text logs (useful for development)

Example JSON log:

{
  "level": "info",
  "ts": "2024-01-15T10:30:00Z",
  "msg": "HTTPRoute reconciled",
  "route": "default/my-app",
  "hostnames": ["app.example.com"]
}

Health Endpoints

The controller exposes health endpoints for Kubernetes probes:

Endpoint Port Description
/healthz 8081 Liveness probe
/readyz 8081 Readiness probe

These are used by Kubernetes to determine pod health:

livenessProbe:
  httpGet:
    path: /healthz
    port: 8081
readinessProbe:
  httpGet:
    path: /readyz
    port: 8081

Metrics Endpoint

The controller exposes Prometheus metrics on the metrics port:

Endpoint Port Description
/metrics 8080 Prometheus metrics

See Metrics & Alerting for available metrics.