{"id":13688737,"url":"https://github.com/jittering/traefik-kop","last_synced_at":"2026-02-02T21:35:37.200Z","repository":{"id":37234241,"uuid":"433983192","full_name":"jittering/traefik-kop","owner":"jittering","description":"A dynamic docker-\u003eredis-\u003etraefik discovery agent","archived":false,"fork":false,"pushed_at":"2024-07-11T13:32:52.000Z","size":256,"stargazers_count":162,"open_issues_count":2,"forks_count":13,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-08-03T15:12:04.296Z","etag":null,"topics":["docker","redis","traefik","traefik-docker"],"latest_commit_sha":null,"homepage":"","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/jittering.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2021-12-01T20:59:37.000Z","updated_at":"2024-08-03T12:22:05.000Z","dependencies_parsed_at":"2024-01-14T16:07:30.224Z","dependency_job_id":"fbea437a-ee42-4a27-985e-0565d8bdd2e5","html_url":"https://github.com/jittering/traefik-kop","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jittering%2Ftraefik-kop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jittering%2Ftraefik-kop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jittering%2Ftraefik-kop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jittering%2Ftraefik-kop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jittering","download_url":"https://codeload.github.com/jittering/traefik-kop/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224274828,"owners_count":17284651,"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":["docker","redis","traefik","traefik-docker"],"created_at":"2024-08-02T15:01:21.462Z","updated_at":"2026-02-02T21:35:37.187Z","avatar_url":"https://github.com/jittering.png","language":"Go","funding_links":[],"categories":["docker"],"sub_categories":[],"readme":"# traefik-kop\n\nA dynamic docker-\u003eredis-\u003etraefik discovery agent.\n\nSolves the problem of running a non-Swarm/Kubernetes multi-host cluster with a\nsingle public-facing traefik instance.\n\n```text\n                        +---------------------+          +---------------------+\n                        |                     |          |                     |\n+---------+     :443    |  +---------+        |   :8088  |  +------------+     |\n|   WAN   |---------------\u003e| traefik |\u003c--------------------\u003e| svc-nginx  |     |\n+---------+             |  +---------+        |          |  +------------+     |\n                        |       |             |          |                     |\n                        |  +---------+        |          |  +-------------+    |\n                        |  |  redis  |\u003c--------------------\u003e| traefik-kop |    |\n                        |  +---------+        |          |  +-------------+    |\n                        |             docker1 |          |             docker2 |\n                        +---------------------+          +---------------------+\n```\n\n`traefik-kop` solves this problem by using the same `traefik` docker-provider\nlogic. It reads the container labels from the local docker node and publishes\nthem to a given `redis` instance. Simply configure your `traefik` node with a\n`redis` provider and point it to the same instance, as in the diagram above.\n\n## Contents\n\n- [traefik-kop](#traefik-kop)\n  - [Contents](#contents)\n  - [Usage](#usage)\n  - [Configuration](#configuration)\n  - [IP Binding](#ip-binding)\n    - [bind-ip](#bind-ip)\n    - [bind-interface](#bind-interface)\n    - [traefik-kop service labels](#traefik-kop-service-labels)\n    - [Container Networking](#container-networking)\n    - [Disable IP Replacement (auto-detection)](#disable-ip-replacement-auto-detection)\n  - [Load Balancer Merging](#load-balancer-merging)\n  - [Service port binding](#service-port-binding)\n  - [Namespaces](#namespaces)\n    - [Namespace via label prefix](#namespace-via-label-prefix)\n  - [Docker API](#docker-api)\n    - [Traefik Docker Provider Config](#traefik-docker-provider-config)\n  - [Releasing](#releasing)\n  - [License](#license)\n\n## Usage\n\nConfigure `traefik` to use the redis provider, for example via `traefik.yml`:\n\n```yaml\nproviders:\n  providersThrottleDuration: 2s\n  docker:\n    watch: true\n    endpoint: unix:///var/run/docker.sock\n    swarmModeRefreshSeconds: 15s\n    exposedByDefault: false\n  redis:\n    endpoints:\n      # assumes a redis link with this service name running on the same\n      # docker host as traefik\n      - \"redis:6379\"\n```\n\nRun `traefik-kop` on your other nodes via docker-compose:\n\n```yaml\nservices:\n  traefik-kop:\n    image: \"ghcr.io/jittering/traefik-kop:latest\"\n    restart: unless-stopped\n    volumes:\n      - /var/run/docker.sock:/var/run/docker.sock\n    environment:\n      - \"REDIS_ADDR=192.168.1.50:6379\"\n      - \"BIND_IP=192.168.1.75\"\n      # Alternatively, derive from an interface (requires network_mode: host)\n      # - \"BIND_INTERFACE=eth0\"\n```\n\nThen add the usual labels to your target service:\n\n```yml\nservices:\n  nginx:\n    image: \"nginx:alpine\"\n    restart: unless-stopped\n    ports:\n      # The host port binding will automatically be picked up for use as the\n      # service endpoint. See 'service port binding' in the configuration\n      # section for more.\n      - 8088:80\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.nginx.rule=Host(`nginx-on-docker2.example.com`)\"\n      - \"traefik.http.routers.nginx.tls=true\"\n      - \"traefik.http.routers.nginx.tls.certresolver=default\"\n      # [opptional] explicitly set the port binding for this service.\n      # See 'service port binding' in the configuration section for more.\n      - \"traefik.http.services.nginx.loadbalancer.server.scheme=http\"\n      - \"traefik.http.services.nginx.loadbalancer.server.port=8088\"\n```\n\nSee also the [IP Binding](#ip-binding) section below.\n\n## Configuration\n\ntraefik-kop can be configured via either CLI flags or environment variables.\n\n```text\nUSAGE:\n   traefik-kop [global options] command [command options] [arguments...]\n\nGLOBAL OPTIONS:\n   --hostname value       Hostname to identify this node in redis (default: \"server.local\") [$KOP_HOSTNAME]\n   --bind-ip value        IP address to bind services to [$BIND_IP]\n   --bind-interface value Network interface to derive bind IP (overrides auto-detect) [$BIND_INTERFACE]\n   --skip-replace         Disable custom IP replacement (default: false) [$SKIP_REPLACE]\n   --redis-addr value     Redis address (default: \"127.0.0.1:6379\") [$REDIS_ADDR]\n   --redis-user value     Redis username (default: \"default\") [$REDIS_USER]\n   --redis-pass value     Redis password (if needed) [$REDIS_PASS]\n   --redis-db value       Redis DB number (default: 0) [$REDIS_DB]\n   --redis-ttl value      Redis TTL (in seconds) (default: 0) [$REDIS_TTL]\n   --docker-host value    Docker endpoint (default: \"unix:///var/run/docker.sock\") [$DOCKER_ADDR]\n   --docker-config value  Docker provider config (file must end in .yaml) [$DOCKER_CONFIG]\n   --docker-prefix value  Docker label prefix [$DOCKER_PREFIX]\n   --poll-interval value  Poll interval for refreshing container list (default: 60) [$KOP_POLL_INTERVAL]\n   --namespace value      Namespace to process containers for [$NAMESPACE]\n   --verbose              Enable debug logging (default: false) [$VERBOSE, $DEBUG]\n   --help, -h             show help\n   --version, -V          Print the version (default: false)\n```\n\nMost important are the `bind-ip`/`bind-interface` and `redis-addr` flags.\n\n## IP Binding\n\nThere are a number of ways to set the IP published to traefik. Below is the\norder of precedence (highest first) and detailed descriptions of each setting.\n\n1. `kop.\u003cservice name\u003e.bind.ip` label\n2. `kop.bind.ip` label\n3. Container networking IP\n4. `--bind-ip` CLI flag (or `BIND_IP` env var)\n5. `--bind-interface` CLI flag (or `BIND_INTERFACE` env var), requires network_mode: host\n6. Auto-detected host IP\n\n### bind-ip\n\nSince your upstream docker nodes are external to your primary traefik server,\ntraefik needs to connect to these services via the server's public IP rather\nthan the usual method of using the internal docker-network IPs (by default\n172.20.0.x or similar).\n\nWhen using host networking this can be auto-detected, however it is advisable in\nthe majority of cases to manually set this to the desired IP address. This can\nbe done using the docker image by exporting the `BIND_IP` environment variable.\n\n### bind-interface\n\nIf you prefer to bind using the primary IPv4 address of a specific network\ninterface, you can specify it via `--bind-interface` or the `BIND_INTERFACE`\nenvironment variable, for example `--bind-interface eth0`. This is used when\n`--bind-ip` is not provided. If the interface has multiple addresses, the first\nnon-loopback IPv4 address is selected.\n\nThis option requires that the container be run with  `network_mode: host` so that the interface is visible to the container.\n\n### traefik-kop service labels\n\nThe bind IP can be set via label for each service/container.\n\nLabels can be one of two keys:\n\n- `kop.\u003cservice name\u003e.bind.ip=2.2.2.2`\n- `kop.bind.ip=2.2.2.2`\n\nFor a container with a single exposed service, or where all services use\nthe same IP, the latter is sufficient.\n\n### Container Networking\n\nIf your container is configured to use a network-routable IP address via an\noverlay network or CNI plugin, that address will override the `bind-ip`\nconfiguration above when the `traefik.docker.network` label is present on the\nservice.\n\nIf using a global overlay `network` in your [Traefik Docker Provider\nConfig](#traefik-docker-provider-config), it is recommended that you [disable IP\nreplacement](#disable-ip-replacement-auto-detection) entirely (see below).\n\n### Disable IP Replacement (auto-detection)\n\ntraefik-kop's custom IP and port auto-detection can be disabled by passing the `--skip-replace` flag\nor setting the `SKIP_REPLACE=1` environment variable. When set, `traefik-kop` will rely solely on\ntraefik's native IP and port detection. Other relevant flags such as `--bind-ip` or `--bind-interface`\nwill have no effect.\n\nThis works best when your services are using an overlay network, as described in\n[Container Networking](#container-networking) above.\n\n## Load Balancer Merging\n\nIf your service is running on multiple nodes and load balanced by traefik, you can enable\nmerging of load balancers by adding the following label to your container:\n\n- `kop.merge-lbs=true`\n\nWhen set, kop will check in redis for an existing definition and, if found, append it's service\naddress to the ones already present.\n\nThis setting is off by default as there are some cases where it could cause an issue, such as if\nyour node's IP changes. In this case, the dead IP would be left in place and the new IP would get\nadded to the list, causing some of your traffic to fail.\n\n## Service port binding\n\nBy default, the service port will be picked up from the container port bindings\nif only a single port is bound. For example:\n\n```yml\nservices:\n  nginx:\n    image: \"nginx:alpine\"\n    restart: unless-stopped\n    ports:\n      - 8088:80\n```\n\n`8088` would automatically be used as the service endpoint's port in traefik. If\nyou have more than one port or are using *host networking*, you will need to\nexplicitly set the port binding via service label, like so:\n\n```yaml\nservices:\n  nginx:\n    image: \"nginx:alpine\"\n    network_mode: host\n    ports:\n      - 8088:80\n      - 8888:81\n    labels:\n      # (note: other labels snipped for brevity)\n      - \"traefik.http.services.nginx.loadbalancer.server.port=8088\"\n```\n\n__NOTE:__ unlike the standard traefik-docker usage, we need to expose the\nservice port on the host and tell traefik to bind to *that* port (8088 in the\nexample above) in the load balancer config, not the internal port (80). This is\nso that traefik can reach it over the network.\n\n## Namespaces\n\ntraefik-kop has the ability to target containers via namespaces(s). Simply\nconfigure `kop` with a namespace:\n\n```yaml\nservices:\n  traefik-kop:\n    image: \"ghcr.io/jittering/traefik-kop:latest\"\n    restart: unless-stopped\n    volumes:\n      - /var/run/docker.sock:/var/run/docker.sock\n    environment:\n      - \"REDIS_ADDR=192.168.1.50:6379\"\n      - \"BIND_IP=192.168.1.75\"\n      - \"NAMESPACE=staging\"\n```\n\nThen add the `kop.namespace` label to your target services, along with the usual traefik labels:\n\n```yaml\nservices:\n  nginx:\n    image: \"nginx:alpine\"\n    restart: unless-stopped\n    ports:\n      - 8088:80\n    labels:\n      - \"kop.namespace=staging\"\n      - \"traefik.enable=true\"\n      - \"traefik...\"\n```\n\nMultiple namespaces can be used by comma-delimiting your values. Traefik-kop will include a container as long as one of its namespaces is found.\n\n```yaml\nservices:\n  traefik-kop:\n    # ...\n    environment:\n      # will expose any service with either 'dev' or 'staging'\n      - \"NAMESPACE=dev,staging\"\n```\n\n```yaml\nservices:\n  nginx:\n    # ...\n    labels:\n      # will be exposed because it has namespace 'staging'\n      - \"kop.namespace=staging,experimental\"\n```\n\n### Namespace via label prefix\n\nAn alternative method of namespacing is to add a custom prefix for your traefik-related labels. This\nworks as an *inclusion* filter for `traefik-kop` and an *exclusion* filter for `traefik`. This can\nbe useful in a scenario here you are running both `traefik` and `traefik-kop` side-by-side on the\nsame host.\n\n```yaml\nservices:\n  nginx:\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers...\"\n      - \"traefik...\"\n```\n\nbecomes\n\n```yaml\nservices:\n  traefik-kop:\n    image: \"ghcr.io/jittering/traefik-kop:latest\"\n    restart: unless-stopped\n    volumes:\n      - /var/run/docker.sock:/var/run/docker.sock\n    environment:\n      - \"REDIS_ADDR=192.168.1.50:6379\"\n      - \"BIND_IP=192.168.1.75\"\n      - \"DOCKER_PREFIX=kop.public\"\n\n  nginx:\n    labels:\n      - \"kop.public.traefik.enable=true\"\n      - \"kop.public.traefik.http.routers...\"\n      - \"kop.public.traefik...\"\n```\n\n## Docker API\n\ntraefik-kop expects to connect to the Docker host API via a unix socket, by\ndefault at `/var/run/docker.sock`. The location can be overridden via the\n`DOCKER_ADDR` env var or `--docker-host` flag.\n\nOther connection methods (like ssh, http/s) are not supported.\n\nBy default, `traefik-kop` will listen for push events via the Docker API in\norder to detect configuration changes. In some circumstances, a change may not\nbe pushed correctly. For example, when using healthchecks in certain\nconfigurations, the `start -\u003e healthy` change may not be detected via push\nevent. As a failsafe, there is an additional polling mechanism to detect those\nmissed changes.\n\nThe default interval of 60 seconds should be light so as not to cause any\nissues, however it can be adjusted as needed via the `KOP_POLL_INTERVAL` env var\nor set to 0 to disable it completely.\n\n### Traefik Docker Provider Config\n\nIn addition to the simple `--docker-host` setting above, all [Docker Provider\nconfiguration\noptions](https://doc.traefik.io/traefik/providers/docker/#provider-configuration)\nare available via the `--docker-config \u003cfilename.yaml\u003e` flag which expects\neither a filename to read configuration from or an inline YAML document.\n\nFor example:\n\n```yaml\nservices:\n  traefik-kop:\n    image: \"ghcr.io/jittering/traefik-kop:latest\"\n    restart: unless-stopped\n    volumes:\n      - /var/run/docker.sock:/var/run/docker.sock\n    environment:\n      REDIS_ADDR: \"172.28.183.97:6380\"\n      BIND_IP: \"172.28.183.97\"\n      DOCKER_CONFIG: |\n        ---\n        docker:\n          defaultRule: Host(`{{.Name}}.foo.example.com`)\n```\n\n## Releasing\n\nTo release a new version, simply push a new tag to github.\n\n```sh\ngit push\ngit tag -a v0.11.0\ngit push --tags\n```\n\nTo update the changelog:\n\n```sh\nmake update-changelog\n# or (replace tag below)\ndocker run -it --rm -v \"$(pwd)\":/usr/local/src/your-app \\\n  githubchangeloggenerator/github-changelog-generator \\\n  -u jittering -p traefik-kop --output \"\" \\\n  --since-tag v0.10.1\n```\n\n## License\n\ntraefik-kop: MIT, (c) 2015, Pixelcop Research, Inc.\n\ntraefik: MIT, (c) 2016-2025 Containous SAS; 2020-2022 Traefik Labs\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjittering%2Ftraefik-kop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjittering%2Ftraefik-kop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjittering%2Ftraefik-kop/lists"}