{"record":{"id":"0abafca31b0664c3","repo":"tailscale/tailscale","slug":"experimental-allow-proxying-cluster-traffic-via-in-0abafc","errorCode":null,"errorMessage":"EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS is set but POD_IP is not set","messagePattern":"EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS is set but POD_IP is not set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/containerboot/settings.go","lineNumber":322,"sourceCode":"\t\treturn errors.New(\"TS_ID_TOKEN and TS_CLIENT_SECRET cannot both be set\")\n\t}\n\tif s.IDToken != \"\" && s.Audience != \"\" {\n\t\treturn errors.New(\"TS_ID_TOKEN and TS_AUDIENCE cannot both be set\")\n\t}\n\tif s.Audience != \"\" && s.ClientSecret != \"\" {\n\t\treturn errors.New(\"TS_AUDIENCE and TS_CLIENT_SECRET cannot both be set\")\n\t}\n\tif s.AuthKey != \"\" && (s.ClientID != \"\" || s.ClientSecret != \"\" || s.IDToken != \"\" || s.Audience != \"\") {\n\t\treturn errors.New(\"TS_AUTHKEY cannot be used with TS_CLIENT_ID, TS_CLIENT_SECRET, TS_ID_TOKEN, or TS_AUDIENCE.\")\n\t}\n\tif s.AllowProxyingClusterTrafficViaIngress && s.UserspaceMode {\n\t\treturn errors.New(\"EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS is not supported in userspace mode\")\n\t}\n\tif s.AllowProxyingClusterTrafficViaIngress && s.ServeConfigPath == \"\" {\n\t\treturn errors.New(\"EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS is set but this is not a cluster ingress proxy\")\n\t}\n\tif s.AllowProxyingClusterTrafficViaIngress && s.PodIP == \"\" {\n\t\treturn errors.New(\"EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS is set but POD_IP is not set\")\n\t}\n\tif s.EnableForwardingOptimizations && s.UserspaceMode {\n\t\treturn errors.New(\"TS_EXPERIMENTAL_ENABLE_FORWARDING_OPTIMIZATIONS is not supported in userspace mode\")\n\t}\n\tif s.HealthCheckAddrPort != \"\" {\n\t\tlog.Printf(\"[warning] TS_HEALTHCHECK_ADDR_PORT is deprecated and will be removed in 1.82.0. Please use TS_ENABLE_HEALTH_CHECK and optionally TS_LOCAL_ADDR_PORT instead.\")\n\t\tif _, err := netip.ParseAddrPort(s.HealthCheckAddrPort); err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing TS_HEALTHCHECK_ADDR_PORT value %q: %w\", s.HealthCheckAddrPort, err)\n\t\t}\n\t}\n\tif s.localMetricsEnabled() || s.localHealthEnabled() || s.EgressProxiesCfgPath != \"\" {\n\t\tif _, err := netip.ParseAddrPort(s.LocalAddrPort); err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing TS_LOCAL_ADDR_PORT value %q: %w\", s.LocalAddrPort, err)\n\t\t}\n\t}\n\tif s.DebugAddrPort != \"\" {\n\t\tif _, err := netip.ParseAddrPort(s.DebugAddrPort); err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing TS_DEBUG_ADDR_PORT value %q: %w\", s.DebugAddrPort, err)","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/tailscale/tailscale/blob/cfe32b8be6a33f8e24fbc369cbfbf7c729d9e042/cmd/containerboot/settings.go#L304-L340","documentation":"Thrown by containerboot (the Tailscale container entrypoint) during startup settings validation. EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS turns a Tailscale ingress proxy into a proxy for cluster-internal traffic, which requires knowing the pod's own IP to intercept and forward traffic correctly. That IP is read exclusively from the POD_IP environment variable (cmd/containerboot/settings.go:128), so enabling the feature with POD_IP unset aborts startup before tailscaled launches.","triggerScenarios":"Container starts with EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS set to a truthy value while POD_IP is unset/empty. Typical causes: the downward-API env block was omitted from the pod spec, the variable was misspelled (POD_IP vs POD_IPS, the latter being a separate multi-IP setting), or the manifest was copied from a Kubernetes deployment into docker run where no downward API exists.","commonSituations":"Porting an ingress-proxy StatefulSet between charts and dropping the fieldRef block; renaming env vars during upgrades; attempting to run the experimental cluster-traffic proxying feature outside Kubernetes where no kubelet populates status.podIP.","solutions":["Add a POD_IP env var via the Kubernetes downward API: env: [{name: POD_IP, valueFrom: {fieldRef: {fieldPath: status.podIP}}}]","Check the spelling: it must be POD_IP (singular); POD_IPS is a different variable and does not satisfy this check","If you did not intend to proxy cluster traffic through this ingress proxy, unset EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS","Confirm the pod is scheduled in Kubernetes so the kubelet actually populates status.podIP"],"exampleFix":"# before (pod env)\nenv:\n  - name: EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS\n    value: 'true'\n\n# after\nenv:\n  - name: EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS\n    value: 'true'\n  - name: POD_IP\n    valueFrom:\n      fieldRef:\n        fieldPath: status.podIP","handlingStrategy":"validation","validationCode":"#!/usr/bin/env bash\n# Fail fast before container start when proxying cluster traffic is enabled.\nset -euo pipefail\nif [[ \"${EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS:-}\" == \"true\" ]]; then\n  if [[ -z \"${POD_IP:-}\" ]]; then\n    echo 'POD_IP must be set (downward API: status.podIP) when EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS=true' >&2\n    exit 1\n  fi\nfi","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the POD_IP downward-API env block adjacent to the feature flag in the same manifest so they are removed or copied together","Add a pod-spec lint (conftest/kubeconform custom rule) that rejects manifests enabling the feature without a POD_IP fieldRef","Use kubectl describe pod to confirm POD_IP is actually populated before rolling the flag out fleet-wide"],"tags":["kubernetes","containerboot","configuration","environment-variables","ingress-proxy"],"backgroundTag":null,"analyzedSha":"cfe32b8be6a33f8e24fbc369cbfbf7c729d9e042","analyzedAt":"2026-08-15T19:58:31.583Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}