A lightweight GitHub webhook server. It listens for signed POST requests, validates them, and runs a configured shell command.
cargo build --release
webhook [OPTIONS]
webhook --config /etc/webhook/webhook.conf
All options can be set via CLI flags or an INI configuration file. CLI flags take precedence.
INI format with the following sections:
[server]
bind = 0.0.0.0
port = 9000
[hooks]
config_dir = /etc/webhook/hooks.d
script_timeout = 30
[logging]
log_level = info
[limits]
max_body_size = 2097152Pass the file path with --config.
Each hook is a YAML file in the hooks directory. The filename (without extension) is the hook ID and determines the endpoint path.
# /etc/webhook/hooks.d/deploy.yaml → POST /hooks/deploy
secret: your-webhook-secret
validate:
headers:
X-GitHub-Event: push
payload:
repository.name: myrepo
command: /usr/local/bin/deploy.shFields:
| Field | Required | Description |
|---|---|---|
secret |
yes | HMAC-SHA256 secret matching the GitHub webhook secret |
validate.headers |
no | Header name/value pairs that must match exactly |
validate.payload |
no | Dot-notation JSON paths that must match given values |
command |
yes | Shell command to execute on a valid request |
Header names in validate.headers are case-insensitive.
Payload paths use dot notation: repository.name matches {"repository": {"name": "..."}}.
Requests must be signed with X-Hub-Signature-256: sha256=<hmac-sha256-hex> using the hook's secret.
The command is run via sh -c with the following environment:
| Variable | Value |
|---|---|
WEBHOOK_HOOK_ID |
Hook ID (filename stem) |
WEBHOOK_EVENT |
Value of X-GitHub-Event header |
WEBHOOK_DELIVERY |
Value of X-GitHub-Delivery header |
WEBHOOK_PAYLOAD |
Raw request body (also written to stdin) |
The working directory is inherited from the server process. A non-zero exit code is treated as failure and returns HTTP 500.
A service unit is provided in debian/service. It runs as a dedicated webhook user with the config at /etc/webhook/webhook.conf and the working directory /etc/webhook (so relative script paths resolve there).
Log level is controlled by log_level in the config (or --log-level). Set to debug for per-request access logs and script execution details. The RUST_LOG environment variable overrides the configured level.
| Level | Events |
|---|---|
info |
Startup, successful webhook dispatch |
warn |
Validation failures, authentication errors |
error |
Script failures and timeouts |
debug |
HTTP access, script spawn and exit |