> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Webhook Receiver

> Guide to configure Flux Receiver and GitHub webhooks to trigger immediate GitRepository reconciliation in a Kubernetes cluster demo.

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:

* Flux notification controller: [https://fluxcd.io/docs/components/notification/](https://fluxcd.io/docs/components/notification/)
* Flux GitRepository source: [https://fluxcd.io/docs/components/source/gitrepositories/](https://fluxcd.io/docs/components/source/gitrepositories/)
* GitHub webhooks: [https://docs.github.com/en/developers/webhooks-and-events/about-webhooks](https://docs.github.com/en/developers/webhooks-and-events/about-webhooks)

## Quick prerequisites table

| Item | Purpose | Example / Command |
| - | - | - |
| Cluster with Flux | Runs Flux controllers including notification-controller | See Flux install docs |
| Repo checkout | Modify manifests and push changes | `git checkout 2-demo` |
| Tunnel for demo | Exposes a NodePort to GitHub (demo only) | `npx localtunnel --port <NODEPORT>` |

## 1) Switch to the demo branch and inspect pods

Switch to the `2-demo` branch and list pods in the `2-demo` namespace:

```bash theme={null}
# switch branch
git checkout 2-demo

# check pods in namespace
kubectl -n 2-demo get po
```

Example output:

```text theme={null}
NAME                            READY   STATUS    RESTARTS         AGE
block-buster-75f7754b9-cjjxm    1/1     Running   3 (7h50m ago)     23h
```

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`:

```yaml theme={null}
app: block-buster
version: 7.2.0
env: dev
name: block-buster
namespace: 2-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: block-buster
  strategy: {}
  template:
    metadata:
      labels:
        app: block-buster
        api: downward
        usage: global
```

If your editor cannot save due to permissions, fix file permissions or save with elevated privileges. Example error you might see:

```text theme={null}
Failed to save 'deployment.yml': Unable to write file ... (Error: EACCES: permission denied, open '/home/batman/.../deployment.yml')
```

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:

```yaml theme={null}
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
  name: 2-demo-source-git-bb-app
  namespace: flux-system
spec:
  interval: 1m0s
  ref:
    branch: 2-demo
  url: https://github.com/sidd-harth-2/bb-app-source
```

Watch the GitRepository source (it will show when Flux stores a new artifact):

```bash theme={null}
flux get sources git 2-demo-source-git-bb-app -w
```

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:

```bash theme={null}
kubectl -n flux-system expose deployment notification-controller \
  --name receiver \
  --port 80 \
  --target-port 9292 \
  --type NodePort
```

Verify services in the `flux-system` namespace:

```bash theme={null}
kubectl -n flux-system get svc
```

Example output:

```text theme={null}
NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE
notification-controller  ClusterIP   10.108.140.1    `none`         80/TCP          24h
receiver                 NodePort    10.107.229.12   `none`         80:30847/TCP    8s
source-controller        ClusterIP   10.100.3.149    `none`         80/TCP          24h
webhook-receiver         ClusterIP   10.106.47.73    `none`         80/TCP          24h
```

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:

```bash theme={null}
kubectl -n flux-system create secret generic github-webhook-token \
  --from-literal=token='dont-share-this-secret'
```

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:

```bash theme={null}
cd ../block-buster/flux-clusters/dev-cluster/

flux create receiver github-webhook-receiver \
  --type github \
  --event ping,push \
  --secret-ref github-webhook-token \
  --resource GitRepository/2-demo-source-git-bb-app \
  --export > github-webhook-receiver.yml
```

The exported YAML will look like:

```yaml theme={null}
apiVersion: notification.toolkit.fluxcd.io/v1beta2
kind: Receiver
metadata:
  name: github-webhook-receiver
  namespace: flux-system
spec:
  events:
    - ping
    - push
  resources:
    - kind: GitRepository
      name: 2-demo-source-git-bb-app
  secretRef:
    name: github-webhook-token
  type: github
```

Commit & push `github-webhook-receiver.yml` to the repository Flux watches (e.g., your `flux-clusters` repo), or apply directly with:

```bash theme={null}
kubectl apply -f github-webhook-receiver.yml
```

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:

```bash theme={null}
flux get receivers
```

Example output:

```text theme={null}
NAME                      SUSPENDED  READY  MESSAGE
github-webhook-receiver   False      True   Receiver initialized for path: /hook/ab09b3ac5436ef9fca17e74ddc7d57b24be7943a1e00ee34f45df11b3b73beda
```

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:

```bash theme={null}
# if you have lt installed:
lt --port 30847

# or via npx:
npx localtunnel --port 30847
```

localtunnel will return an HTTPS URL such as:

```text theme={null}
https://tall-windows-guess-49-206-56-103.loca.lt
```

Append the Receiver path reported earlier to form the payload URL:

```text theme={null}
https://tall-windows-guess-49-206-56-103.loca.lt/hook/ab09b3ac5436ef9fca17e74ddc7d57b24be7943a1e00ee34f45df11b3b73beda
```

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:

```text theme={null}
Request URL: https://tall-windows-guess-49-206-56-103.loca.lt/hook/ab09b3ac...
Request method: POST
content-type: application/json
User-Agent: GitHub-Hookshot/...
X-GitHub-Event: ping
X-Hub-Signature: sha1=...
X-Hub-Signature-256: sha256=...
```

![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.](https://mintcdn.com/kodekloud-c4ac6d9a/AyhVWHpoMIYCWiei/images/GitOps-with-FluxCD/Notification-Controller/Demo-Webhook-Receiver/github-webhooks-created-edit-delete.jpg?fit=max\&auto=format\&n=AyhVWHpoMIYCWiei\&q=85\&s=88c9ac9c7252e038b60ae4da433d64b6)

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:

```bash theme={null}
flux get sources git 2-demo-source-git-bb-app -w
```

Now commit and push:

```bash theme={null}
git add manifests/deployment.yml
git commit -m "replicas: 4"
git push origin 2-demo
```

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):

```text theme={null}
NAME                                REVISION                   SUSPENDED  READY    MESSAGE
2-demo-source-git-bb-app            2-demo@sha1:788621ff       False      True     stored artifact for revision '2-demo@sha1:788621ff'
2-demo-source-git-bb-app            2-demo@sha1:c89c9f69       False      True     stored artifact for revision '2-demo@sha1:c89c9f69'
```

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:

* Flux notification controller: [https://fluxcd.io/docs/components/notification/](https://fluxcd.io/docs/components/notification/)
* GitRepository source: [https://fluxcd.io/docs/components/source/gitrepositories/](https://fluxcd.io/docs/components/source/gitrepositories/)
* GitHub Webhooks: [https://docs.github.com/en/developers/webhooks-and-events/about-webhooks](https://docs.github.com/en/developers/webhooks-and-events/about-webhooks)

That's all for this lesson.

> **[Watch Video](https://learn.kodekloud.com/user/courses/gitops-with-fluxcd/module/6f4f2854-e5a5-4f3e-8910-85c47c018029/lesson/12051a70-33b7-49bf-bbce-50145d3fe4c7)**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.