{"record":{"id":"68e46fe53dc24f18","repo":"netbirdio/netbird","slug":"failed-to-bind-free-port-for-ebpf-proxy","errorCode":null,"errorMessage":"failed to bind free port for eBPF proxy","messagePattern":"failed to bind free port for eBPF proxy","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/iface/wgproxy/ebpf/portlookup.go","lineNumber":22,"sourceCode":"\t\"fmt\"\n\t\"net\"\n)\n\nvar (\n\tportRangeStart = 3128\n\tportRangeEnd   = portRangeStart + 100\n)\n\ntype portLookup struct {\n}\n\nfunc (pl portLookup) searchFreePort() (int, error) {\n\tfor i := portRangeStart; i <= portRangeEnd; i++ {\n\t\tif pl.tryToBind(i) == nil {\n\t\t\treturn i, nil\n\t\t}\n\t}\n\treturn 0, fmt.Errorf(\"failed to bind free port for eBPF proxy\")\n}\n\nfunc (pl portLookup) tryToBind(port int) error {\n\tl, err := net.ListenPacket(\"udp\", fmt.Sprintf(\":%d\", port))\n\tif err != nil {\n\t\treturn err\n\t}\n\t_ = l.Close()\n\treturn nil\n}\n","sourceCodeStart":4,"sourceCodeEnd":33,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/iface/wgproxy/ebpf/portlookup.go#L4-L33","documentation":"Returned by portLookup.searchFreePort when every UDP port in the hardcoded range 3128-3228 (portRangeStart=3128, +100) failed a trial net.ListenPacket(\"udp\", \":port\") bind. The eBPF WireGuard proxy needs one free loopback UDP port in this fixed window because the eBPF program is loaded with a specific proxy port that kernel and userspace must agree on. When all 101 candidates are taken, Listen() aborts.","triggerScenarios":"WGEBPFProxy.Listen() calling searchFreePort while another process (most commonly a second NetBird agent instance, or Squid, which defaults to TCP/3128 but other proxies scan this range too) holds every UDP port in 3128-3228, or UDP socket creation is blocked (socket/memory limits, seccomp in a hardened container).","commonSituations":"Two netbird daemons on one host (system service plus manually launched binary); a caching proxy or test suite squatting the 3128 range; containers with very low UDP buffer/socket limits; SELinux/seccomp denying UDP binds.","solutions":["Find the squatter and stop it: `ss -uapn | awk '$5 ~ /:31[0-9][0-9]|:32[0-2][0-9]/'` or `lsof -i UDP:3128-3228`","Ensure only one agent instance runs: `pgrep -a netbird` and stop the duplicate service/container","Free the range and retry starting the agent (the search is only done once per Listen call, so a restart is required)","If the host legitimately needs those ports, run the agent where the range is free or disable the eBPF path so the userspace UDP proxy is used"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// preflight: is the eBPF proxy port window usable?\nfunc proxyRangeFree() bool {\n    for p := 3128; p <= 3228; p++ {\n        if l, err := net.ListenPacket(\"udp\", fmt.Sprintf(\":%d\", p)); err == nil {\n            _ = l.Close()\n            return true\n        }\n    }\n    return false\n}","typeGuard":null,"tryCatchPattern":"if err := wgProxy.Listen(); err != nil {\n    if strings.Contains(err.Error(), \"failed to bind free port for eBPF proxy\") {\n        log.Warn(\"eBPF proxy port window busy, falling back to userspace UDP proxy\")\n        wgProxy = udpProxy // run without eBPF acceleration\n    } else {\n        return err\n    }\n}","preventionTips":["Run exactly one netbird agent per host; check `pgrep -a netbird` before starting","Reserve UDP 3128-3228 on hosts that run the agent (avoid Squid-style proxies in that window)","Automate the preflight bind check above in deployment scripts so failures surface before `netbird up`"],"tags":["go","netbird","ebpf","port-binding","udp","linux"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}