Featured image of post How to create a webhook

How to create a webhook

How to setup webhooks on Ubuntu/Debian Server for triggering custom Bash scripts

🎧 Prefer audio?

Listen to the podcast version:

My goal is to create a simple webhook that will run a custom Bash script on every POST request.
The webhook must be secured with a token.

What is a Webhook?

In short: A webhook is an automatic notification sent from one system to another when a specific event occurs.

Tip

Think of it like a doorbell: when someone presses the button (an event happens), the bell rings (a message is sent) to let you know.

In webhooks, when an event (like a new commit to a code repository) happens, a message (usually an HTTP request) is sent to a specific web address (URL) you set up. This lets your server know right away, so it can do something automatically, like start a deployment.

Setting Up a Webhook

To keep it simple, I will use a lightweight webhook server, written in Go:
webhook (Github repo). The documentation and examples are available here.

Webhook Installation

The webhook server is available as an apt package.

sudo apt update && sudo apt upgrade
sudo apt install webhook

Configure a Webhook Endpoint

sudo mkdir -p /etc/webhook
sudo vi /etc/webhook/hooks.json

Now, let’s create a simple hook that will run only if the provided token is correct:

[
  {
    "id": "test-hook",
    "execute-command": "/usr/local/bin/webhook/test-hook.sh",
    "response-message": "Executing test webhook...",
    "trigger-rule": {
      "match": {
        "type": "value",
        "value": "secret-token-value",
        "parameter": {
          "source": "url",
          "name": "token"
        }
      }
    }
  }
]

Create a Sample Script to Be Executed

For demonstration I will create a simple script, that will log a datetime of it’s execution.

sudo mkdir -p /usr/local/bin/webhook
sudo vi /usr/local/bin/webhook/test-hook.sh
#!/bin/bash
LOG_FILE="/var/log/webhook_test.log"

echo "[Webhook Triggered] $(date '+%F %T')" >> "$LOG_FILE"

Make script executable:

sudo chmod 750 /usr/local/bin/webhook/test-hook.sh

Run the Webhook

The webhook service runs on port 9000 by default. If you want to use a different port, specify the -p port_number option.

webhook -hooks /etc/webhook/hooks.json -verbose

Create a systemd webhook.service

To make it persistent with systemd you have to create a service unit.

sudo vi /etc/systemd/system/webhook.service
[Unit]
Description=Webhook Listener
After=network.target

[Service]
ExecStart=/usr/bin/webhook -hooks /etc/webhook/hooks.json -verbose
Restart=always

[Install]
WantedBy=multi-user.target

Activate a webhook service:

sudo systemctl daemon-reload
sudo systemctl enable --now webhook.service
sudo systemctl start webhook.service

Configure an Nginx Server

Add a simple Nginx proxy configuration, to pass request to port 9000.

sudo vi /etc/nginx/sites-available/webhook
server {
    server_name webhook.example.com;
    listen 80;
    return 302 https://$server_name$request_uri;
}
server {
    listen 443 ssl;
    server_name webhook.example.com;

    ssl_certificate         /etc/nginx/ssl/webhook.example.com.crt;
    ssl_certificate_key     /etc/nginx/ssl/webhook.example.com.key;

    access_log /var/log/nginx/webhook.access.log;
    error_log /var/log/nginx/webhook.error.log;

    location / {
        proxy_pass         http://127.0.0.1:9000/hooks/;
        proxy_http_version 1.1;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;

        # Optional: Prevent POST flooding
        limit_except POST {
            deny all;
        }
    }
}

Now, create a symbolic link to enable the site, and test the new configuration:

sudo ln -s /etc/nginx/sites-available/webhook /etc/nginx/sites-enabled/
sudo nginx -t

If nginx does not report any errors, reload:

sudo nginx -s reload

Webhook Testing

Call the hook with the token:

curl -X POST "https://webhook.example.com/test-hook?token=secret-token-value"

You should receive a response from the server:
Executing test webhook...

This confirms that the script execution was triggered successfully.
If you look into the log file, you should see the script output:
[Webhook Triggered] 2025-07-14 12:00:02

Summary

In this tutorial, you learned how to set up a secure webhook on an Ubuntu server using the lightweight webhook server.

You configured a webhook endpoint protected by a token, created a Bash script to be triggered by incoming POST requests, and set up systemd to run the webhook service persistently.

Additionally, you configured Nginx as a reverse proxy to securely expose your webhook endpoint over HTTPS.
Finally, you tested the setup to ensure everything works as expected. This approach provides a simple, secure, and automated way to trigger custom scripts on your server in response to external events.

👍 Good job!

Built with Hugo + customized Stack theme