go-proxyproto
A Go library that implements the HAProxy PROXY protocol (v1 and v2) for TCP, Unix, and UDP listeners.
Repository Health
Technical Analysis
go-proxyproto is a Go implementation of the HAProxy PROXY protocol specification, covering both the text-based version 1 and the binary version 2 formats. It preserves the original client connection information (source and destination address, port, and transport) as traffic crosses NAT gateways, load balancers, and other proxy layers that would otherwise present every connection as coming from the proxy itself.
The library wraps a standard net.Listener with proxyproto.Listener so accepted connections report the real client address transparently to existing code, and it exposes lower-level Header, Read, and ParseUDPDatagram APIs for writing headers, parsing them out of band, or handling UDP datagrams where each packet must carry its own header. Trust is explicit: policies (REQUIRE, USE, IGNORE, REJECT, SKIP) and CIDR-based trusted-source helpers decide which upstreams are allowed to supply proxy information, since anyone permitted to send a header can spoof the address it carries.
What You Get
- A drop-in net.Listener wrapper (proxyproto.Listener) that transparently unwraps PROXY headers so conn.RemoteAddr() returns the real client address
- Support for both PROXY protocol v1 (text) and v2 (binary), including TLVs and vendor-specific extensions (AWS, Azure, GCP, SSL/TLS TLVs) via the tlvparse subpackage
- Configurable trust policies (REQUIRE, USE, IGNORE, REJECT, SKIP) plus CIDR-range helpers like TrustProxyHeaderFromRanges to restrict which upstreams may supply proxy headers
- Dedicated UDP helpers (ParseUDPDatagram, Header.FormatUDPDatagram) since PROXY protocol over UDP requires the header to be parsed independently from every datagram
- An HTTP/1 and HTTP/2 helper package (helper/http2) that lets a single server accept both PROXY-wrapped protocols behind the same listener
- Runnable example programs for client, server, HTTP server, TLS client/server, and UDP client/server usage under examples/
Common Use Cases
- Recovering the real client IP at a Go TCP or HTTP server sitting behind AWS/GCP/Azure load balancers or HAProxy/Envoy proxies
- Chaining PROXY protocol with TLS termination, in either order, so client address information survives alongside encryption
- Building multi-protocol edge servers that must accept both PROXY-wrapped HTTP/1 and HTTP/2 traffic on one listener
- Implementing UDP-based services (e.g. DNS, syslog relays) that need per-datagram client address recovery under PROXY protocol v2
- Restricting which upstream proxies are trusted to supply client addresses, to prevent IP spoofing on internet-facing listeners
Under The Hood
Architecture go-proxyproto is organized as a flat, single-purpose package (proxyproto) built around three layers: header parsing/writing (header.go, v1.go, v2.go) implements the wire format for both protocol versions; policy.go defines the trust model (PolicyFunc/ConnPolicyFunc, the USE/IGNORE/REJECT/REQUIRE/SKIP enum, and CIDR-based TrustProxyHeaderFromRanges helpers) that decides whether an upstream’s header is honored; and protocol.go ties them together in Listener and Conn, which wrap a net.Listener/net.Conn so RemoteAddr() transparently reflects the client address once the header is read. UDP is deliberately kept out of the stream-oriented Listener/Conn types (udp.go exposes ParseUDPDatagram and Header.FormatUDPDatagram instead) because the spec requires a header in every datagram rather than once per connection, and a subpackage (tlvparse) isolates vendor-specific TLV decoding (AWS, Azure, GCP, SSL) from the core header logic. A separate helper/http2 subpackage layers HTTP/1 and HTTP/2 support on top via an internal pipeListener, keeping HTTP-specific concerns out of the core protocol implementation. Read/write paths are timeout-bound (ReadHeaderTimeout, default 10s) so a single slow or malicious connection cannot indefinitely hold a goroutine during header detection.
Tech Stack The library targets Go 1.25 and depends on only golang.org/x/net (for HTTP/2 support in the helper package) plus its indirect golang.org/x/text dependency — the core protocol implementation itself uses only the Go standard library (net, bufio, sync/atomic, time). It has no runtime framework dependency; it is designed to wrap the standard net.Listener/net.Conn interfaces directly so it drops into any existing TCP, Unix-socket, or HTTP server. CI runs against Go 1.25 and 1.26 via GitHub Actions, and releases are tagged directly against the module’s semantic version.
Code Quality The project has extensive test coverage: dedicated _test.go files for every wire-format and policy source file (header, v1, v2, policy, udp, tlv, addr_proto), package-level example tests (example_conn_test.go, example_listener_test.go, example_tls_test.go, example_udp_test.go) that double as documentation, and a fuzz_test.go exercising the parser against malformed input. Errors are explicit sentinel values (errors.New, wrapped with ErrInvalidUpstream) rather than panics, except for one intentional panic guarding a caller-configuration mistake (setting both Policy and ConnPolicy). Linting is enforced via golangci-lint with an above-default linter set (gosec, bodyclose, revive, misspell, unconvert, and more) run in CI on every push and pull request, alongside go vet and go fmt checks.
What Makes It Unique Unlike libraries that only parse a PROXY header once per connection, go-proxyproto explicitly separates connection-oriented and datagram-oriented handling — UDP support is a distinct API (ParseUDPDatagram/FormatUDPDatagram) rather than an awkward fit forced into the same Listener abstraction, reflecting a close reading of where the specification’s per-datagram requirement diverges from typical stream semantics. Its trust model is unusually explicit for a networking library: rather than assuming a header should always be honored, it documents the spoofing risk directly in the API (REQUIRE still honors headers from any peer) and ships CIDR-based helpers so operators can restrict trust to known proxy ranges without writing custom policy functions. Bundled TLV parsers for AWS, Azure, and GCP vendor extensions, plus a dedicated AWS Network Load Balancer caveat documented directly in the README (the on_first_ack_with_payload timing issue for server-first protocols), show the maintainers tracking real deployment friction beyond the base spec.
Used by 7 apps in this directory
authentik
Authentication · Security
The self-hosted Identity Provider that replaces Okta, Auth0, and Entra ID with a unified SSO platform supporting SAML, OAuth2/OIDC, LDAP, RADIUS, and WebAuthn.
Caddy
Devops · Security
The only web server that obtains and renews TLS certificates automatically, with HTTP/1-2-3 support and zero dependency on external runtimes.
frp
Networking
A fast reverse proxy that exposes local servers behind NAT or firewalls to the public internet with multi-protocol support.
NetBird
Security
Replace your VPN with a zero-trust WireGuard overlay network that auto-connects devices, enforces SSO and posture checks, and deploys in under 5 minutes.
Stormkit
Devops · Hosting Control Panel
Self-hostable platform for deploying and hosting modern web apps with automated CI/CD, custom domains, and a built-in serverless runtime — a true open-source alternative to Vercel and Netlify.
Traefik
Devops · Automation · Security
A cloud-native reverse proxy and load balancer that auto-configures itself from Docker, Kubernetes, and other orchestrators — zero manual routing required.
Tyk API Gateway
Developer Tools · Devops
Cloud-native, high-performance open-source API gateway for REST, GraphQL, gRPC, and TCP — built in Go since 2014 with no feature lockout.