{"id":16370762,"url":"https://github.com/integralist/go-reverse-proxy","last_synced_at":"2025-03-23T02:34:05.227Z","repository":{"id":57496786,"uuid":"142480073","full_name":"Integralist/go-reverse-proxy","owner":"Integralist","description":"Reverse proxy with simple routing configuration and override behaviour","archived":false,"fork":false,"pushed_at":"2018-11-30T16:46:17.000Z","size":14,"stargazers_count":28,"open_issues_count":2,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-18T17:04:04.193Z","etag":null,"topics":["go","golang","gorilla-mux","makefile","proxy-server","reverse-proxy","routing","vegeta"],"latest_commit_sha":null,"homepage":"https://www.integralist.co.uk/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Integralist.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-07-26T18:37:49.000Z","updated_at":"2024-12-01T00:18:16.000Z","dependencies_parsed_at":"2022-09-03T02:30:42.581Z","dependency_job_id":null,"html_url":"https://github.com/Integralist/go-reverse-proxy","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Integralist%2Fgo-reverse-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Integralist%2Fgo-reverse-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Integralist%2Fgo-reverse-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Integralist%2Fgo-reverse-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Integralist","download_url":"https://codeload.github.com/Integralist/go-reverse-proxy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245048012,"owners_count":20552431,"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":["go","golang","gorilla-mux","makefile","proxy-server","reverse-proxy","routing","vegeta"],"created_at":"2024-10-11T03:05:55.647Z","updated_at":"2025-03-23T02:34:04.986Z","avatar_url":"https://github.com/Integralist.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Go Reverse Proxy\n\nA simple configuration-driven reverse proxy written in Go.\n\nIt has zero dependencies outside of the Go standard library.\n\n## Configuration\n\nDefine a slice of type `Config`, with the minimum set of fields being: `Path` and `Upstream`.\n\nConfiguration is defined in the [routing/configuration](./routing/configuration.go) file.\n\nUpstreams are defined in the [upstreams](./upstreams/upstreams.go) file.\n\n## Example Config\n\nBelow we explain the actual [routing configuration](./routing/configuration.go) committed into this repo...\n\n- [Proxy Request](#proxy-request)\n- [Proxy Request using Regular Expression](#proxy-request-using-regular-expression)\n- [Proxy Request with Modified Path](#proxy-request-with-modified-path)\n- [Override with Modified Path](#override-with-modified-path)\n- [Modified Path + Override with Modified Path](#modified-path--override-with-modified-path)\n- [Override to Different Upstream](#override-to-different-upstream)\n- [Query String Override](#query-string-override)\n- [Query String Override with Regular Expression](#query-string-override-with-regular-expression)\n\n### Proxy Request\n\n```go\nConfig{\n  Path:     \"/anything/standard\",\n  Upstream: upstreams.HTTPBin,\n}\n```\n\n### Requests\n\n- `/anything/standard`\n\n### Result\n\nThe request will be proxied straight through to the specified upstream without any modifications.\n\n---\n\n### Proxy Request using Regular Expression\n\n```go\nConfig{\n  Path:     \"/anything/(?:foo|bar)$\",\n  Upstream: upstreams.HTTPBin,\n}\n```\n\n### Requests\n\n- `/anything/foo`\n- `/anything/bar`\n\n### Result\n\nBoth requests will be proxied straight through to the specified upstream without any modifications.\n\n---\n\n### Proxy Request with Modified Path\n\n```go\nConfig{\n  Path:       `/(?P\u003ccap\u003efoo\\w{3})`,\n  Upstream:   upstreams.HTTPBin,\n  ModifyPath: \"/anything/${cap}\",\n}\n```\n\n### Requests\n\n- `/fooabc`\n- `/fooxyz`\n\n### Result\n\nBoth requests will be proxied through to the specified upstream but the path will be modified to include the captured information: `/anything/abc` and `/anything/xyz`.\n\n---\n\n### Override with Modified Path\n\n```go\nConfig{\n  Path:     \"/(?P\u003cstart\u003eanything)/(?P\u003ccap\u003efoobar)$\",\n  Upstream: upstreams.HTTPBin,\n  Override: Override{\n    Header:     \"X-BF-Testing\",\n    Match:      \"integralist\",\n    ModifyPath: \"/anything/newthing${cap}\",\n  },\n}\n```\n\n### Requests\n\n- `/anything/foobar`\n- `/anything/foobar` (+ HTTP Request Header `X-BF-Testing: integralist`)\n\n### Result\n\nThe request will be proxied straight through to the specified upstream without any modifications. \n\nIf the relevant request header is specified, then the request will be proxied through to the specified upstream but the path will be modified to include the captured information: `/anything/newthingfoobar`.\n\n---\n\n### Modified Path + Override with Modified Path\n\n```go\nConfig{\n  Path:       \"/(?P\u003ccap\u003edouble-checks)$\",\n  Upstream:   upstreams.HTTPBin,\n  ModifyPath: \"/anything/toplevel-modified-${cap}\",\n  Override: Override{\n    Header:     \"X-BF-Testing\",\n    Match:      \"integralist\",\n    ModifyPath: \"/anything/override-modified-${cap}\",\n  },\n}\n```\n\n### Requests\n\n- `/double-checks`\n- `/double-checks` (+ HTTP Request Header `X-BF-Testing: integralist`)\n\n### Result\n\nThe request will be proxied through to the specified upstream but the path will be modified to include the captured information: `/anything/toplevel-modified-double-checks`. \n\nIf the relevant request header is specified, then the request will be proxied through to the specified upstream but the path will be modified to include the captured information: `/anything/override-modified-double-checks`.\n\n---\n\n### Override to Different Upstream\n\n```go\nConfig{\n  Path:     \"/anything/(?P\u003ccap\u003eintegralist)\",\n  Upstream: upstreams.HTTPBin,\n  Override: Override{\n    Header:     \"X-BF-Testing\",\n    Match:      \"integralist\",\n    ModifyPath: \"/about\",\n    Upstream:   upstreams.Integralist,\n  },\n}\n```\n\n### Requests\n\n- `/anything/integralist`\n- `/anything/integralist` (+ HTTP Request Header `X-BF-Testing: integralist`)\n\n### Result\n\nThe request will be proxied straight through to the specified upstream without any modifications. \n\nIf the relevant request header is specified, then the request will be proxied through to a _different_ specified upstream and the path will also be modified.\n\n\u003e Note: although we use a named capture group, we don't actually utilise it anywhere in the rest of the configuration, so it's effectively a no-op.\n\n---\n\n### Query String Override\n\n```go\nConfig{\n  Path:     \"/about\",\n  Upstream: upstreams.HTTPBin,\n  Override: Override{\n    Query:    \"s\",\n    Match:    \"integralist\",\n    Upstream: upstreams.Integralist,\n  },\n}\n```\n\n### Requests\n\n- `/about`\n- `/about?s=integralist`\n\n### Result\n\nThe request will be proxied straight through to the specified upstream without any modifications. \n\nIf the relevant query parameter is specified, then the request will be proxied through to a _different_ specified upstream.\n\n---\n\n### Query String Override with Regular Expression\n\n```go\nConfig{\n  Path:     \"/anything/querytest\",\n  Upstream: upstreams.HTTPBin,\n  Override: Override{\n    Query:      \"s\",\n    Match:      `integralist(?P\u003ccap\u003e\\d{1,3})$`,\n    MatchType:  \"regex\",\n    ModifyPath: \"/anything/newthing${cap}\",\n  },\n}\n```\n\n### Requests\n\n- `/anything/querytest`\n- `/anything/querytest?s=integralist123`\n- `/anything/querytest?s=integralist456`\n\n### Result\n\nThe first request will be proxied straight through to the specified upstream without any modifications. \n\nIf the relevant query parameter is specified, then the second and third requests will have their path modified to include the captured information: `/anything/newthing123` and `/anything/newthing456`. \n\n## Response Headers\n\nWe set the following response headers (not all will be set depending on the configuration):\n\n```\nX-Forwarded-Host\nX-Origin-Host\nX-Router-Upstream\nX-Router-Upstream-OriginalHost\nX-Router-Upstream-OriginalPath\nX-Router-Upstream-OriginalPathModified\nX-Router-Upstream-Override\nX-Router-Upstream-OverrideHost\nX-Router-Upstream-OverridePath\n```\n\n## Usage\n\n```\nmake run\n```\n\n\u003e Note: the application listens on port `9001`.\n\n```\ncurl -v http://localhost:9001/some/path/you/configured\n```\n\n## Tests\n\n```\nmake test\n```\n\n## Load Test\n\nWe use [`vegeta`](https://github.com/tsenart/vegeta) for load testing, so make sure you have that installed.\n\n```\nmake stress\n```\n\nExample output:\n\n```\nRequests      [total, rate]            1500, 50.03\nDuration      [total, attack, wait]    30.11237994s, 29.982166788s, 130.213152ms\nLatencies     [mean, 50, 95, 99, max]  154.522948ms, 96.76258ms, 358.770472ms, 1.076826656s, 2.954136535s\nBytes In      [total, mean]            2039772, 1359.85\nBytes Out     [total, mean]            0, 0.00\nSuccess       [ratio]                  100.00%\nStatus Codes  [code:count]             200:1500\nError Set:\n```\n\n## TODO\n\n- Look at implementing thread pool processing on a host or server basis.\n- Verify if DNS caching (or request memoization) would affect latency results?\n- Review 301 redirect behaviour to be sure we don't need to handle that differently.\n- Flesh out some unit tests (not just integration testing)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintegralist%2Fgo-reverse-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fintegralist%2Fgo-reverse-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintegralist%2Fgo-reverse-proxy/lists"}