{"record":{"id":"6e98a72a478d2da2","repo":"netbirdio/netbird","slug":"proxy-protocol-is-not-supported-for-udp-services","errorCode":null,"errorMessage":"proxy_protocol is not supported for UDP services","messagePattern":"proxy_protocol is not supported for UDP services","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"management/internals/modules/reverseproxy/service/service.go","lineNumber":931,"sourceCode":"\t}\n\tif s.ListenPort != 0 {\n\t\treturn errors.New(\"listen_port is not supported for HTTP services\")\n\t}\n\treturn s.validateHTTPTargets()\n}\n\nfunc (s *Service) validateTCPUDPMode() error {\n\tif s.Domain == \"\" {\n\t\treturn errors.New(\"domain is required for TCP/UDP services (used for cluster derivation)\")\n\t}\n\tif s.isAuthEnabled() {\n\t\treturn errors.New(\"auth is not supported for TCP/UDP services\")\n\t}\n\tif len(s.Targets) != 1 {\n\t\treturn errors.New(\"TCP/UDP services must have exactly one target\")\n\t}\n\tif s.Mode == ModeUDP && s.Targets[0].ProxyProtocol {\n\t\treturn errors.New(\"proxy_protocol is not supported for UDP services\")\n\t}\n\treturn s.validateL4Target(s.Targets[0])\n}\n\nfunc (s *Service) validateTLSMode() error {\n\tif s.Domain == \"\" {\n\t\treturn errors.New(\"domain is required for TLS services (used for SNI matching)\")\n\t}\n\tif s.isAuthEnabled() {\n\t\treturn errors.New(\"auth is not supported for TLS services\")\n\t}\n\tif s.ListenPort == 0 {\n\t\treturn errors.New(\"listen_port is required for TLS services\")\n\t}\n\tif len(s.Targets) != 1 {\n\t\treturn errors.New(\"TLS services must have exactly one target\")\n\t}\n\treturn s.validateL4Target(s.Targets[0])","sourceCodeStart":913,"sourceCodeEnd":949,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/management/internals/modules/reverseproxy/service/service.go#L913-L949","documentation":"Returned by validateTCPUDPMode when mode is \"udp\" and the single target has proxy_protocol=true. The PROXY protocol prepends a client-address header to a TCP connection; UDP has no connection or byte-stream framing to carry it, so the flag is meaningless and rejected. TCP targets may keep proxy_protocol=true to convey the real client IP to the upstream.","triggerScenarios":"Creating a udp service with targets[0].proxy_protocol set to true, typically copied from a working TCP service definition that needed client-IP propagation.","commonSituations":"Duplicating a TCP forward that used proxy_protocol (e.g. in front of an nginx/haproxy expecting it) for a QUIC/Game/UDP service and leaving the flag on. Hoping to log real client IPs for UDP traffic.","solutions":["Set proxy_protocol to false (or omit it) on the UDP target.","Keep proxy_protocol=true only on TCP targets whose upstream actually parses the PROXY v1 header.","For client identity on UDP, rely on NetBird's network/flow logging rather than the PROXY protocol."],"exampleFix":"// before\n{ \"mode\": \"udp\", \"listen_port\": 3478,\n  \"targets\": [ { \"target_id\": \"peer-a\", \"port\": 3478, \"proxy_protocol\": true } ] }\n\n// after\n{ \"mode\": \"udp\", \"listen_port\": 3478,\n  \"targets\": [ { \"target_id\": \"peer-a\", \"port\": 3478, \"proxy_protocol\": false } ] }","handlingStrategy":"validation","validationCode":"func checkUDPNoProxyProtocol(mode string, proxyProtocol bool) error {\n\tif mode == \"udp\" && proxyProtocol {\n\t\treturn errors.New(\"proxy_protocol must be false for udp services\")\n\t}\n\treturn nil\n}","typeGuard":"func isUDPProxyProtocolClean(mode string, proxyProtocol bool) bool {\n\treturn mode != \"udp\" || !proxyProtocol\n}","tryCatchPattern":"if err := svc.Validate(); err != nil {\n\tif strings.Contains(err.Error(), \"proxy_protocol is not supported for UDP\") {\n\t\treturn respondBadRequest(errors.New(\"set proxy_protocol false on the udp target\"))\n\t}\n\treturn respondBadRequest(err)\n}","preventionTips":["Default proxy_protocol to false and enable it per-target only for TCP behind a PROXY-aware upstream.","Document in service templates that PROXY protocol is TCP-only (v1 text header needs a stream).","Lint UDP service configs for the flag in CI before they hit the API."],"tags":["netbird","reverse-proxy","validation","udp","proxy-protocol","l4","go"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}