tailscale/tailscale · error

installing egress proxy rules: %w

Error message

installing egress proxy rules: %w

What it means

Egress proxying to a fixed tailnet IP (TS_DEST_IP holding a tailnet address): when this node's tailnet IPs changed, installEgressForwardingRule (forwarding.go:98) programs DNAT, SNAT and MSS clamp for cfg.TailnetTargetIP. This fatal error wraps the netfilter failure or the 'no tailscale IP matching family' family mismatch from forwarding.go:115.

Source

Thrown at cmd/containerboot/main.go:862

				var cd string
				if nmState.certDomains.Len() != 0 {
					cd = nmState.certDomains.At(0)
				}
				if cd == "" {
					cd = kubetypes.ValueNoHTTPS
				}
				prev := certDomain.Swap(new(cd))
				if prev == nil || *prev != cd {
					select {
					case certDomainChanged <- true:
					default:
					}
				}
			}
			if cfg.TailnetTargetIP != "" && ipsHaveChanged && len(addrs) != 0 {
				log.Printf("Installing forwarding rules for destination %v", cfg.TailnetTargetIP)
				if err := installEgressForwardingRule(ctx, cfg.TailnetTargetIP, addrs, nfr); err != nil {
					return fmt.Errorf("installing egress proxy rules: %w", err)
				}
			}
			// If this is a L7 cluster ingress proxy (set up
			// by Kubernetes operator) and proxying of
			// cluster traffic to the ingress target is
			// enabled, set up proxy rule each time the
			// tailnet IPs of this node change (including
			// the first time they become available).
			if cfg.AllowProxyingClusterTrafficViaIngress && cfg.ServeConfigPath != "" && ipsHaveChanged && len(addrs) != 0 {
				log.Printf("installing rules to forward traffic for %s to node's tailnet IP", cfg.PodIP)
				if err := installTSForwardingRuleForDestination(ctx, cfg.PodIP, addrs, nfr); err != nil {
					return fmt.Errorf("installing rules to forward traffic to node's tailnet IP: %w", err)
				}
			}
			currentIPs = newCurrentIPs

			// Only store device FQDN and IP addresses to
			// Kubernetes Secret when any required proxy

View on GitHub (pinned to cfe32b8be6)

Solutions

  1. Check the wrapped error to distinguish family mismatch from netfilter failure
  2. Match families: give the node a tailnet address of the same family as TS_DEST_IP
  3. Ensure NET_ADMIN and correct TS_FIREWALL_MODE
  4. Validate that the target IP is a single-host address reachable in the tailnet
Defensive patterns

Strategy: validation

Validate before calling

# TS_DEST_IP family must exist among the node's own tailnet addrs
if echo "$TS_DEST_IP" | grep -q ':'; then test -n "$(tailscale ip -6)" || echo 'proxy needs a v6 tailnet addr'; else test -n "$(tailscale ip -4)" || echo 'proxy needs a v4 tailnet addr'; fi

Prevention

When it happens

Trigger: DNATNonTailscaleTraffic / EnsureSNATForDst / ClampMSSToPMTU failing due to missing capabilities or firewall mode; TailnetTargetIP family (v4 vs v6) not present among the node's own tailnet addresses.

Common situations: IPv6 tailnet target with an IPv4-only proxy node; NET_ADMIN dropped from the pod spec; host switched firewall stack after initial deployment.

Related errors


AI-assisted analysis of tailscale/tailscale@cfe32b8be6 (2026-08-15). Data as JSON: /api/errors/b779d7d595e86747. Report an issue: GitHub.