Skip to main content
In this lesson you’ll learn how to use the Flux notification controller’s Receiver API to trigger immediate reconciliation via GitHub webhooks. Instead of waiting for a GitRepository’s polling interval, a webhook notifies Flux to fetch and apply the latest commit as soon as you push. Prerequisites:
  • A Kubernetes cluster with Flux and the notification controller installed.
  • A clone of the demo repository (we’ll use the 2-demo branch in this guide).
  • Access to the GitHub repository where you’ll add the webhook.
Useful links:

Quick prerequisites table

1) Switch to the demo branch and inspect pods

Switch to the 2-demo branch and list pods in the 2-demo namespace:
Example output:
Confirm the current replica count and pod status before making changes.

2) Update the Deployment (replicas -> 2)

Edit your application manifest (for example manifests/deployment.yml) and update the replica count to 2:
If your editor cannot save due to permissions, fix file permissions or save with elevated privileges. Example error you might see:
Resolve permission issues before committing.

3) Observe Flux GitRepository polling interval

Flux stores artifacts from your Git repository according to the interval on the GitRepository resource. A typical resource looks like this:
Watch the GitRepository source (it will show when Flux stores a new artifact):
If interval is 1m0s, Flux polls every 60 seconds and may take up to ~60s to detect a commit. Set a longer interval to reduce polling frequency, or use a webhook to trigger immediate reconciliation.

4) Expose the notification controller (provide a payload URL)

To allow GitHub to POST to your cluster, expose the Flux notification controller. For this demo we’ll create a NodePort service called receiver that routes to the notification controller’s port:
Verify services in the flux-system namespace:
Example output:
Note the NodePort mapping — in this example the receiver service maps port 80 to node port 30847 (80:30847/TCP).
Exposing the notification controller with a NodePort is fine for demos and testing. For production, prefer a LoadBalancer, Ingress, or authenticated proxy with TLS and proper access controls.

5) Create a webhook secret in the cluster

Create a Kubernetes Secret in the flux-system namespace to hold your GitHub webhook secret. Flux uses this to validate incoming webhook payloads:
Replace 'dont-share-this-secret' with a strong secret and keep it secure. You will use this same secret value in the GitHub webhook configuration.
Keep webhook secrets confidential. If a secret is exposed, rotate it immediately and update both the Kubernetes Secret and the GitHub webhook configuration.

6) Create a Flux Receiver for GitHub webhooks

Create a Receiver resource that accepts GitHub ping and push events and targets your GitRepository resource. Generate the YAML using the Flux CLI and export it to a file:
The exported YAML will look like:
Commit & push github-webhook-receiver.yml to the repository Flux watches (e.g., your flux-clusters repo), or apply directly with:
Apply the Receiver in the same cluster where the notification controller runs.

7) Inspect the Receiver and get the webhook path

After the Receiver is reconciled, Flux reports the path that the notification controller listens on. Check the receivers:
Example output:
Combine an externally reachable host with this path to build the webhook payload URL. The host is an endpoint that reaches the receiver service (a LoadBalancer IP, Ingress hostname, or a tunnel URL in demos).

8) Expose NodePort via localtunnel (demo only) and create the GitHub webhook

To make the NodePort reachable from GitHub (for demo/testing), use a tunneling service like localtunnel:
localtunnel will return an HTTPS URL such as:
Append the Receiver path reported earlier to form the payload URL:
In your GitHub repository settings -> Webhooks, create a new webhook with:
  • Payload URL: the URL above
  • Content type: application/json
  • Secret: the same secret value stored in the github-webhook-token Secret
  • Events: choose “Just the push event” (or select ping + push if desired)
GitHub will send a test ping to validate delivery. Example webhook request headers:
A dark-themed GitHub repository settings page showing the "Webhooks" section, with a banner saying a hook was successfully created. One webhook URL is listed with Edit and Delete buttons visible.
You can view delivery status and response codes in GitHub’s webhook delivery logs — a 200 response means the cluster accepted the webhook.

9) Push a change and observe immediate reconciliation

Make a further change to your application manifest (for example change replicas: 2 to replicas: 4), then commit and push to the 2-demo branch. First, watch the GitRepository to observe when Flux stores the new artifact:
Now commit and push:
With the webhook configured, GitHub will POST the push event to the Receiver. The notification controller validates the signature using your secret and triggers Flux to fetch the new artifact. You should see the source update within seconds: Example observed behavior (fast reconciliation via webhook):
Compare this to the earlier ~60s poll interval — webhooks trigger near-instant reconciliation.

10) Summary and best practices

  • Flux polls Git repositories according to the interval on the GitRepository resource (e.g., 1m0s).
  • Use a Flux Receiver + notification controller to reconcile immediately on push events from GitHub.
  • Store the webhook secret in a Kubernetes Secret and use it to validate incoming payloads.
  • For demos, exposing the notification controller via NodePort + tunnel (localtunnel, ngrok) works fine. For production, expose the service with a LoadBalancer, Ingress, or authenticated proxy (TLS + proper access control).
  • Rotate webhook secrets if they are ever exposed, and restrict webhook endpoints with network policies or authentication where appropriate.
Further reading: That’s all for this lesson.

Watch Video