{"id":13820752,"url":"https://github.com/fluxcd/flux-recv","last_synced_at":"2026-01-14T23:40:43.311Z","repository":{"id":36295172,"uuid":"221231444","full_name":"fluxcd/flux-recv","owner":"fluxcd","description":"Webhook receiver for Flux v1","archived":true,"fork":false,"pushed_at":"2022-01-07T17:37:45.000Z","size":171,"stargazers_count":64,"open_issues_count":5,"forks_count":14,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-16T10:41:07.650Z","etag":null,"topics":[],"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/fluxcd.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":"2019-11-12T14:01:28.000Z","updated_at":"2024-10-02T09:14:07.000Z","dependencies_parsed_at":"2022-08-26T05:21:37.867Z","dependency_job_id":null,"html_url":"https://github.com/fluxcd/flux-recv","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/fluxcd/flux-recv","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxcd%2Fflux-recv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxcd%2Fflux-recv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxcd%2Fflux-recv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxcd%2Fflux-recv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fluxcd","download_url":"https://codeload.github.com/fluxcd/flux-recv/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxcd%2Fflux-recv/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28439432,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T22:37:52.437Z","status":"ssl_error","status_checked_at":"2026-01-14T22:37:31.496Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2024-08-04T08:01:08.305Z","updated_at":"2026-01-14T23:40:43.286Z","avatar_url":"https://github.com/fluxcd.png","language":"Go","funding_links":[],"categories":["others"],"sub_categories":[],"readme":"[![CircleCI](https://circleci.com/gh/fluxcd/flux-recv.svg?style=svg)](https://circleci.com/gh/fluxcd/flux-recv)\n\n# Flux webhook receiver\n\nThe container image built herein acts as a webhook endpoint, that will\nnotify Flux of git push and image push events.\n\nFlux has a `notify` method in its API, but this is unsuitable to\nexposing to the internet, because\n\n - it handles a payload defined by the Flux API, rather than handling\n   the events posted by GitHub etc.\n - to use it as a webhook endpoint, you would have to expose the Flux\n   API listener to the internet; and that is terribly, terribly\n   unsafe.\n\n## Supported webhook sources\n\n`flux-recv` understands\n\n - `GitHub` push events (and ping events)\n - `DockerHub` image push events\n - `Quay` image push events\n - `GitLab` push events\n - `Bitbucket` push events\n - `GoogleContainerRegistry` image push events via pubsub\n - `Nexus` image push events\n\nSome of these have specific configuration options; see\n[Source-specific configuration](#source-specific-configuration) below.\n\n## How to use it\n\nIn short:\n\n - construct a configuration, including shared secrets\n - run `fluxcd/flux-recv` as a sidecar in the flux deployment\n - expose the flux-recv listener to the internet\n - install webhooks at the source provider (e.g., GitHub)\n - check if it works\n\nThese are explained in more depth in the following sections.\n\n### Constructing a configuration\n\nEach webhook you want to receive must have its own shared secret,\nwhich is supplied as a file mounted into the container.\n\nIn addition, there is a config YAML that tells `flux-recv` which\nsecrets correspond to which kinds of webhook, so it knows what to\nexpect.\n\nHere is how to make a Kubernetes Secret with a shared secret and a\nconfiguration in it:\n\n - create the secret -- [GitHub\n   recommends](https://developer.github.com/webhooks/securing/) 20\n   bytes of randomness (NB I am using `print` rather than `puts`\n   because newlines will mess things up):\n\n```\n$ ruby -rsecurerandom -e 'print SecureRandom.hex(20)' \u003e ./github.key\n```\n\n - create a configuration that refers to it:\n\n```sh\n$ cat \u003e\u003e fluxrecv.yaml \u003c\u003cEOF\nfluxRecvVersion: 1\nendpoints:\n- keyPath: github.key\n  source: GitHub\nEOF\n```\n\nThe value of `source` is one of the sources supported (listed above,\nand in [`sources.go`](./sources.go)).\n\n - create a kustomization.yaml that will construct the Secret for you:\n\n```sh\n$ cat \u003e\u003e kustomization.yaml \u003c\u003cEOF\nsecretGenerator:\n- name: fluxrecv-config\n  files:\n  - github.key\n  - fluxrecv.yaml\ngeneratorOptions:\n  disableNameSuffixHash: true\nEOF\n```\n\n - use kubectl to apply the kustomization:\n\n```sh\nkubectl apply -k .\n```\n\nYou now have a Kubernetes secret named `fluxrecv-config`.\n\n### Running flux-recv as a sidecar\n\nThe ideal is to run `flux-recv` as a sidecar to `fluxd`, so that the\nflux API is only exposed on localhost. The additional bits you need in\nthe flux deployment are:\n\n - a volume definition that refers to the fluxrecv-config constructed\n   above\n - a container spec to run the flux-recv container itself\n\n\nThe first bit goes under `.spec.template.volumes`:\n\n```yaml\n      # volumes:\n\n      - name: fluxrecv-config\n        secret:\n          secretName: fluxrecv-config\n          defaultMode: 0400\n```\n\nThe second bit goes under `.spec.template.containers`:\n\n```yaml\n      # containers:\n\n      - name: recv\n        image: fluxcd/flux-recv:0.4.0\n        imagePullPolicy: IfNotPresent\n        args:\n        - --config=/etc/fluxrecv/fluxrecv.yaml\n        ports:\n        - containerPort: 8080\n        readinessProbe:\n          httpGet:\n            path: /health\n            port: 8080\n        volumeMounts:\n        - name: fluxrecv-config\n          mountPath: /etc/fluxrecv\n```\n\nYou do not need to alter the container spec for the `flux` container,\nthough you may want to supply the argument `--listen=localhost:3030`\nto limit API access to localhost, if you don't already.\n\n\u003e If you do restrict API access to localhost, make sure you also\n\u003e\n\u003e  - supply `--listen-metrics=:3031`\n\u003e  - annotate the pod with `prometheus.io/port: \"3031\"`, so\n\u003e    Prometheus knows which port to scrape).\n\u003e  - remove any probes that rely on reaching the API\n\n### Expose flux-recv to the internet\n\nTo expose the flux-recv listener to the internet so that webhooks can\nreach it, you will need to:\n\n - make a Kubernetes Service for `flux-recv`; and,\n - either\n   - tell an Ingress to route requests to the service; OR\n   - use ngrok to tunnel requests through to flux-recv\n\n#### Making a service for flux-recv\n\nTo be able to route requests to `flux-recv` from anywhere else, it\nneeds a Kubernetes Service. Here's a suitable definition:\n\n```sh\n$ cat \u003e flux-recv-service.yaml \u003c\u003cEOF\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: flux-recv\nspec:\n  type: ClusterIP\n  ports:\n    - name: recv\n      port: 8080\n      targetPort: 8080\n  selector:\n    name: flux\nEOF\n$ kubectl apply -f ./flux-recv-service.yaml\n```\n\nThe selector assumes that your flux deployment (which now includes the\nflux-recv sidecar) has a label `name: flux`.\n\n#### Using an Ingress\n\nIf running in the cloud, you will need to route though an Ingress or\nan analogue, and that will vary depending how you're already using\nthat. However, these things will be in common:\n\n - the URLs at flux-recv are of the form `/hook/\u003cdigest\u003e`, where\n   `\u003cdigest\u003e` is the SHA265 digest of a hook's shared secret,\n   hex-encoded. flux-recv will print out these endpoints when it\n   starts, or you can calculate them with e.g., `sha256 -b\n   ./github.key`;\n\n - the backend will be the `flux-recv` service created previously,\n   with the port `8080`.\n\n#### Using ngrok\n\nIf running locally (e.g., while developing flux-recv itself), it will\nbe more convenient to use `ngrok` to tunnel requests through to your\ncluster.\n\nIn general, ngrok will create a new hostname each time it runs, and\nyou will want to run it in its own deployment so it doesn't get\nrestarted too much.\n\nThe kustomization in [`./example/ngrok`](./example/ngrok/) contains an\n_almost_ complete configuration. You need to obtain an auth token by\nsigning up for an ngrok.com account, and paste it into the field\nindicated in `example/ngrok.yml`, before running\n\n```sh\n$ kubectl apply -k ./example\n```\n\n\u003e Alternatively, you can _not_ sign up to ngrok.com, and remove the\n\u003e volume mount and `-config` arg from the deployment. In this case,\n\u003e you will need to restart ngrok every few hours to get a fresh\n\u003e tunnel, and reinstall any webhooks with the new hostname for the\n\u003e tunnel.\n\nThe _host_ part of your webhook URLs will be something like\n`https://abcd1234.ngrok.io`, and it will change each time ngrok starts\n(which is why we went to some trouble to run it in its own\ndeployment).\n\nThe example ngrok configuration includes a Service with a NodePort, so\nyou can access ngrok's web UI. You may wish to remove the NodePort, or\nthe service entirely, and use `kubectl port-forward` instead.\n\n### Install webhook at the source\n\nEach webhook source has its own user interface or API for installing\nwebhooks. In general though, you will usually need\n\n - a URL for the webhook\n - the shared secret\n\nYou can get the webhook URL for an endpoint by combining the host --\nwhich will depend on how you exposed `flux-recv` to the internet in\nthe previous step -- and the path, which is\n\n    '/hook/' + sha256sum(secret)\n\nYou can see the path in the log output of `flux-recv`, or calculate\nthe digest yourself with, e.g.,\n\n```\n$ sha256sum -b ./github.key\n```\n\nThe webhook URL in total will look something like\n\n    https://abcd1234.ngrok.io/hook/7962c728be656d9580d0ce9bda78320c946d8321a4ba7f31ea15c7f2d471bd26\n\nThe path may differ if you are routing through an ingress or load\nbalancer.\n\nGitHub (and others) require the shared secret, which you can take\ndirectly from the file created in the first step (be careful not to\nintroduce extra characters into the file, if you load it in an\neditor).\n\n### Check if it works\n\nThe easiest way to do this is to watch fluxd's logs, and push a new\ncommit (or image) to the repo for which you installed the hook.\n\n    kubectl logs deploy/flux -f\n\n\nYou should see a log message indicating that fluxd has either\n\n * refreshed the git repo\n\n```\nts=2019-11-20T16:29:26.871873132Z caller=loop.go:127 component=sync-loop event=refreshed url=ssh://git@github.com/squaremo/flux-example\n```\n\n * ignored the notification because it's the wrong branch\n\n```\nts=2019-11-19T15:03:06.477412849Z caller=daemon.go:540 component=daemon msg=\"notified about unrelated change\" url=git@github.com:squaremo/flux-example.git branch=refs/tags/flux-write-check\n```\n\n * scheduled an image repo refresh\n\n```\nts=2019-11-20T16:34:30.134889169Z caller=warming.go:95 component=warmer priority=squaremo/helloworld\n```\n\nSome sources (e.g., GitHub, GitLab) let you test or re-rerun hooks\nfrom their webhook configuration, which can be useful for\ndebugging. If you are using ngrok, it's also possible to re-run a hook\nfrom its dashboard.\n\nIt is safe to re-run hooks, because `fluxd` treats notifications as a\ntrigger to refresh state, rather than as authoritative themselves. For\nexample, when informed of an image push, fluxd does not add the image\nmentioned to its database -- it polls the image registry in question\nto determine whether there is a new image.\n\n### Source-specific configuration\n\n#### Google Container Registry\n\nThe Google Container Registry endpoint expects a [push\nsubscription](https://cloud.google.com/pubsub/docs/push) to be set\nup. If you include a `gcr` field in the endpoint configuration, it\nwill authenticate and verify the audience for incoming webhook\npayloads:\n\n```\nfluxRecvVersion: 1\nendpoints:\n- source: GoogleContainerRegistry\n  keyPath: gcr.key\n  gcr:\n    audience: flux-push-notification\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluxcd%2Fflux-recv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffluxcd%2Fflux-recv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluxcd%2Fflux-recv/lists"}