{"id":13581874,"url":"https://github.com/pires/go-proxyproto","last_synced_at":"2025-05-13T17:08:19.923Z","repository":{"id":38050526,"uuid":"66672939","full_name":"pires/go-proxyproto","owner":"pires","description":"A Go library implementation of the PROXY protocol, versions 1 and 2.","archived":false,"fork":false,"pushed_at":"2025-05-02T21:00:18.000Z","size":238,"stargazers_count":527,"open_issues_count":11,"forks_count":116,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-05-02T21:35:57.606Z","etag":null,"topics":["golang","haproxy","proxy-protocol"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pires.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"pires"}},"created_at":"2016-08-26T19:08:54.000Z","updated_at":"2025-05-02T21:00:14.000Z","dependencies_parsed_at":"2025-04-09T17:16:58.130Z","dependency_job_id":"5bc2f310-695b-47fd-8a19-43b943a3ca21","html_url":"https://github.com/pires/go-proxyproto","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pires%2Fgo-proxyproto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pires%2Fgo-proxyproto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pires%2Fgo-proxyproto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pires%2Fgo-proxyproto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pires","download_url":"https://codeload.github.com/pires/go-proxyproto/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253990466,"owners_count":21995774,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","haproxy","proxy-protocol"],"created_at":"2024-08-01T15:02:17.468Z","updated_at":"2025-05-13T17:08:14.910Z","avatar_url":"https://github.com/pires.png","language":"Go","funding_links":["https://github.com/sponsors/pires"],"categories":["Go"],"sub_categories":[],"readme":"# go-proxyproto\n\n[![Actions Status](https://github.com/pires/go-proxyproto/workflows/test/badge.svg)](https://github.com/pires/go-proxyproto/actions)\n[![Coverage Status](https://coveralls.io/repos/github/pires/go-proxyproto/badge.svg?branch=master)](https://coveralls.io/github/pires/go-proxyproto?branch=master)\n[![Go Report Card](https://goreportcard.com/badge/github.com/pires/go-proxyproto)](https://goreportcard.com/report/github.com/pires/go-proxyproto)\n[![](https://godoc.org/github.com/pires/go-proxyproto?status.svg)](https://pkg.go.dev/github.com/pires/go-proxyproto?tab=doc)\n\n\nA Go library implementation of the [PROXY protocol, versions 1 and 2](https://www.haproxy.org/download/2.3/doc/proxy-protocol.txt),\nwhich provides, as per specification:\n\u003e (...) a convenient way to safely transport connection\n\u003e information such as a client's address across multiple layers of NAT or TCP\n\u003e proxies. It is designed to require little changes to existing components and\n\u003e to limit the performance impact caused by the processing of the transported\n\u003e information.\n\nThis library is to be used in one of or both proxy clients and proxy servers that need to support said protocol.\nBoth protocol versions, 1 (text-based) and 2 (binary-based) are supported.\n\n## Installation\n\n```shell\n$ go get -u github.com/pires/go-proxyproto\n```\n\n## Usage\n\n### Client\n\n```go\npackage main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\n\tproxyproto \"github.com/pires/go-proxyproto\"\n)\n\nfunc chkErr(err error) {\n\tif err != nil {\n\t\tlog.Fatalf(\"Error: %s\", err.Error())\n\t}\n}\n\nfunc main() {\n\t// Dial some proxy listener e.g. https://github.com/mailgun/proxyproto\n\ttarget, err := net.ResolveTCPAddr(\"tcp\", \"127.0.0.1:2319\")\n\tchkErr(err)\n\n\tconn, err := net.DialTCP(\"tcp\", nil, target)\n\tchkErr(err)\n\n\tdefer conn.Close()\n\n\t// Create a proxyprotocol header or use HeaderProxyFromAddrs() if you\n\t// have two conn's\n\theader := \u0026proxyproto.Header{\n\t\tVersion:            1,\n\t\tCommand:            proxyproto.PROXY,\n\t\tTransportProtocol:  proxyproto.TCPv4,\n\t\tSourceAddr: \u0026net.TCPAddr{\n\t\t\tIP:   net.ParseIP(\"10.1.1.1\"),\n\t\t\tPort: 1000,\n\t\t},\n\t\tDestinationAddr: \u0026net.TCPAddr{\n\t\t\tIP:   net.ParseIP(\"20.2.2.2\"),\n\t\t\tPort: 2000,\n\t\t},\n\t}\n\t// After the connection was created write the proxy headers first\n\t_, err = header.WriteTo(conn)\n\tchkErr(err)\n\t// Then your data... e.g.:\n\t_, err = io.WriteString(conn, \"HELO\")\n\tchkErr(err)\n}\n```\n\n### Server\n\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"net\"\n\n\tproxyproto \"github.com/pires/go-proxyproto\"\n)\n\nfunc main() {\n\t// Create a listener\n\taddr := \"localhost:9876\"\n\tlist, err := net.Listen(\"tcp\", addr)\n\tif err != nil {\n\t\tlog.Fatalf(\"couldn't listen to %q: %q\\n\", addr, err.Error())\n\t}\n\n\t// Wrap listener in a proxyproto listener\n\tproxyListener := \u0026proxyproto.Listener{Listener: list}\n\tdefer proxyListener.Close()\n\n\t// Wait for a connection and accept it\n\tconn, err := proxyListener.Accept()\n\tdefer conn.Close()\n\n\t// Print connection details\n\tif conn.LocalAddr() == nil {\n\t\tlog.Fatal(\"couldn't retrieve local address\")\n\t}\n\tlog.Printf(\"local address: %q\", conn.LocalAddr().String())\n\n\tif conn.RemoteAddr() == nil {\n\t\tlog.Fatal(\"couldn't retrieve remote address\")\n\t}\n\tlog.Printf(\"remote address: %q\", conn.RemoteAddr().String())\n}\n```\n\n### HTTP Server\n```go\npackage main\n\nimport (\n\t\"net\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/pires/go-proxyproto\"\n)\n\nfunc main() {\n\tserver := http.Server{\n\t\tAddr: \":8080\",\n\t}\n\n\tln, err := net.Listen(\"tcp\", server.Addr)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tproxyListener := \u0026proxyproto.Listener{\n\t\tListener:          ln,\n\t\tReadHeaderTimeout: 10 * time.Second,\n\t}\n\tdefer proxyListener.Close()\n\n\tserver.Serve(proxyListener)\n}\n```\n\n## Special notes\n\n### AWS\n\nAWS Network Load Balancer (NLB) does not push the PPV2 header until the client starts sending the data. This is a problem if your server speaks first. e.g. SMTP, FTP, SSH etc.\n\nBy default, NLB target group attribute `proxy_protocol_v2.client_to_server.header_placement` has the value `on_first_ack_with_payload`. You need to contact AWS support to change it to `on_first_ack`, instead.\n\nJust to be clear, you need this fix only if your server is designed to speak first.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpires%2Fgo-proxyproto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpires%2Fgo-proxyproto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpires%2Fgo-proxyproto/lists"}