{"id":21929218,"url":"https://github.com/achetronic/hashrouter","last_synced_at":"2025-10-10T08:15:02.020Z","repository":{"id":253409696,"uuid":"843342236","full_name":"achetronic/hashrouter","owner":"achetronic","description":"A zero-dependencies HTTP proxy that truly routes requests hash-consistently","archived":false,"fork":false,"pushed_at":"2025-07-29T11:43:28.000Z","size":456,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-29T13:55:17.381Z","etag":null,"topics":["consistent-hashing","golang","hashring","http","proxy"],"latest_commit_sha":null,"homepage":"","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/achetronic.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-16T09:57:27.000Z","updated_at":"2025-07-29T11:41:56.000Z","dependencies_parsed_at":"2024-09-16T00:10:33.608Z","dependency_job_id":"89f068dc-78d5-4b73-8088-bb51d9db1b7f","html_url":"https://github.com/achetronic/hashrouter","commit_stats":null,"previous_names":["achetronic/hashrouter"],"tags_count":60,"template":false,"template_full_name":null,"purl":"pkg:github/achetronic/hashrouter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achetronic%2Fhashrouter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achetronic%2Fhashrouter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achetronic%2Fhashrouter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achetronic%2Fhashrouter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/achetronic","download_url":"https://codeload.github.com/achetronic/hashrouter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achetronic%2Fhashrouter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279003301,"owners_count":26083555,"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","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["consistent-hashing","golang","hashring","http","proxy"],"created_at":"2024-11-28T22:30:10.428Z","updated_at":"2025-10-10T08:15:02.007Z","avatar_url":"https://github.com/achetronic.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# hashrouter\n\n![GitHub go.mod Go version (subdirectory of monorepo)](https://img.shields.io/github/go-mod/go-version/achetronic/hashrouter)\n![GitHub](https://img.shields.io/github/license/achetronic/hashrouter)\n\n![YouTube Channel Subscribers](https://img.shields.io/youtube/channel/subscribers/UCeSb3yfsPNNVr13YsYNvCAw?label=achetronic\u0026link=http%3A%2F%2Fyoutube.com%2Fachetronic)\n![X (formerly Twitter) Follow](https://img.shields.io/twitter/follow/achetronic?style=flat\u0026logo=twitter\u0026link=https%3A%2F%2Ftwitter.com%2Fachetronic)\n\nA zero-dependencies HTTP proxy that truly routes requests hash-consistently\n\n## Motivation\n\nThis project was created to address a common issue with older proxies that use consistent hashing for request routing. These proxies often fail to maintain real consistency, which can lead to unexpected changes in the backend and increased costs, especially in storage-intensive systems like Varnish.\n\nAdditionally, implementing this solution as a plugin for Nginx or Envoy is challenging because their APIs do not allow flexible changes in routing. Therefore, we developed an independent proxy that uses a consistent hash which only updates when backends actually change, ensuring a more stable request distribution and reducing costs.\n\n## Flags\n\nAs every configuration parameter can be defined in the config file, there are only few flags that can be defined.\nThey are described in the following table:\n\n| Name              | Description                       |      Default      | Example                      |\n|:------------------|:----------------------------------|:-----------------:|:-----------------------------|\n| `--config`        | Path to the YAML config file      | `hashrouter.yaml` | `--config ./hashrouter.yaml` |\n| `--log-level`     | Verbosity level for logs          |      `info`       | `--log-level info`           |\n| `--disable-trace` | Disable showing traces in logs    |      `false`      | `--disable-trace`            |\n| `--metrics-host`  | Host to expose _status_ endpoints |     `0.0.0.0`     | `--metrics-host 0.0.0.0`     |\n| `--metrics-port`  | Port to expose _status_ endpoints |      `2112`       | `--metrics-port 9090`        |\n\n\u003e Output is thrown always in JSON as it is more suitable for automations\n\u003e\n\u003e _Status_ endpoints are located in `/metrics` and `/{proxy-name}/health`\n\n```console\nhashrouter run \\\n    --log-level=info\n    --config=\"./hashrouter.yaml\"\n```\n\n## Examples\n\nHere you have a complete example. More up-to-date one will always be maintained in\n`docs/prototypes` directory [here](./docs/prototypes)\n\n\n```yaml\ncommon:\n  logs:\n    show_access_logs: true\n    enable_request_body_logs: false\n    access_logs_fields:\n    - ${REQUEST:method}\n    - ${REQUEST:host}\n    - ${REQUEST:path}\n    - ${REQUEST:proto}\n    - ${REQUEST:referer}\n\n    # Additionally, body can be logged too.\n    # Please, be extremely careful when doing it: could be giant\n    # For having content in this field, following flag must be enabled: common.logs.enable_request_body_logs\n    - ${REQUEST:body}\n\n    - ${REQUEST_HEADER:user-agent}\n    - ${REQUEST_HEADER:x-forwarded-for}\n    - ${REQUEST_HEADER:x-real-ip}\n\n    - ${RESPONSE_HEADER:content-length}\n    - ${RESPONSE_HEADER:content-type}\n\n    - ${EXTRA:request-id}\n    - ${EXTRA:hashkey}\n    - ${EXTRA:backend}\n\nproxies:\n  - name: varnish\n\n    listener:\n      port: 8080\n      address: 0.0.0.0\n\n    backends:\n      synchronization: 10s\n\n      # ATTENTION:\n      # When the healthchecks are configured, related server is automatically\n      # added (and removed) to the hashring.\n      # During backend outages, this mechanism decreases the latency of responses at the\n      # cost of decreasing the hashring consistency (the router doesn't waste time trying backends in order).\n      # This being said, consider your use case\n\n      static:\n        - name: varnish-01\n          host: 127.0.0.1:8081\n          # (Optional) Healthcheck configuration.\n          #healthcheck:\n          #  timeout: 1s\n          #  retries: 3\n          #  path: /health\n\n        - name: varnish-02\n          host: 127.0.0.1:8082\n          # (Optional) Healthcheck configuration\n          # healthcheck:\n          #   timeout: 1s\n          #   retries: 3\n          #   path: /health\n\n        - name: varnish-03\n          host: 127.0.0.1:8083\n\n      dns:\n        name: varnish-service\n        domain: example.com\n        port: 80\n        # (Optional) Healthcheck configuration\n        # healthcheck:\n        #   timeout: 1s\n        #   retries: 3\n        #   path: /health\n\n    hash_key:\n\n      # Key to generate a hash used to route consistently to the same backend over requests.\n      # It can be composed using headers-based key such as: ${REQUEST_HEADER:\u003cyour-header\u003e}\n      # Or using any of the following:\n      # ${REQUEST:scheme}, ${REQUEST:host}, ${REQUEST:port}, ${REQUEST:path}, ${REQUEST:query}\n      # ${REQUEST:method}, ${REQUEST:proto}\n\n      pattern: \"${REQUEST_HEADER:\u003cyour-header\u003e}${REQUEST:path}\"\n\n    # Aditional options such as hashing mode or TTL\n    options:\n      protocol: http\n\n      # (optional) Maximum time in milliseconds to read the request from the client.\n      # (default: 0ms [no timeout])\n      http_server_read_timeout_ms: 0\n\n      # (optional) Maximum time in milliseconds to write the response to the client.\n      # (default: 0ms [no timeout])\n      http_server_write_timeout_ms: 0\n\n      # (optional) Disable keep alives on the server.\n      # (default: false)\n      http_server_disable_keep_alives: false\n\n      # (optional) Maximum time in milliseconds to wait for the entire backend request to complete,\n      # including both connection and data transfer.\n      # If the request takes longer than this timeout, it will be aborted.\n      # (default: 0ms [no timeout])\n      http_backend_request_timeout_ms: 0\n\n      # (optional) Maximum time in milliseconds to establish a connection with the backend.\n      # If the dial takes longer than this timeout, it will be aborted.\n      # (default: 0ms [no timeout])\n      http_backend_dial_timeout_ms: 0\n\n      # (optional) Time between keep-alive messages on established connection to the backend.\n      # (default: 15s)\n      http_backend_keep_alive_ms: 15000\n\n      # (optional) Disable keep alives to the backend.\n\t    # (default: false)\n      http_backend_disable_keep_alives: false\n\n      # (optional) Hashring always assigns the same backend to the hashkey.\n      # If the backend is down, you can try another backend until exaushting all of them\n      # by enabling this option\n      try_another_backend_on_failure: true\n\n```\n\n\u003e ATTENTION:\n\u003e If you detect some mistake on the config, open an issue to fix it. This way we all will benefit\n\n## How to deploy\n\nThis project is designed specially for Kubernetes, but also provides binary files\nand Docker images to make it easy to be deployed however wanted\n\n### Binaries\n\nBinary files for most popular platforms will be added to the [releases](https://github.com/achetronic/hashrouter/releases)\n\n### Kubernetes\n\nYou can deploy `hashrouter` in Kubernetes using Helm as follows:\n\n```console\nhelm repo add hashrouter https://achetronic.github.io/hashrouter/\n\nhelm upgrade --install --wait hashrouter \\\n  --namespace hashrouter \\\n  --create-namespace achetronic/hashrouter\n```\n\n\u003e More information and Helm packages [here](https://achetronic.github.io/hashrouter/)\n\n\n### Docker\n\nDocker images can be found in GitHub's [packages](https://github.com/achetronic/hashrouter/pkgs/container/hashrouter)\nrelated to this repository\n\n\u003e Do you need it in a different container registry? I think this is not needed, but if I'm wrong, please, let's discuss\n\u003e it in the best place for that: an issue\n\n## How to contribute\n\nWe are open to external collaborations for this project: improvements, bugfixes, whatever.\n\nFor doing it, open an issue to discuss the need of the changes, then:\n\n- Fork the repository\n- Make your changes to the code\n- Open a PR and wait for review\n\nThe code will be reviewed and tested (always)\n\n\u003e We are developers and hate bad code. For that reason we ask you the highest quality\n\u003e on each line of code to improve this project on each iteration.\n\n## License\n\nCopyright 2022.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fachetronic%2Fhashrouter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fachetronic%2Fhashrouter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fachetronic%2Fhashrouter/lists"}