{"id":13563145,"url":"https://github.com/ncarlier/webhookd","last_synced_at":"2025-04-13T01:59:41.378Z","repository":{"id":21114563,"uuid":"24415198","full_name":"ncarlier/webhookd","owner":"ncarlier","description":"A very simple webhook server launching shell scripts.","archived":false,"fork":false,"pushed_at":"2025-01-12T08:17:36.000Z","size":448,"stargazers_count":963,"open_issues_count":7,"forks_count":89,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-13T01:59:33.899Z","etag":null,"topics":["api-rest","bash","cd","ci","continuous-deployment","continuous-integration","go","shell-script","webhook","webhook-server"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ncarlier.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-09-24T13:05:46.000Z","updated_at":"2025-04-10T12:12:37.000Z","dependencies_parsed_at":"2023-01-12T03:30:40.977Z","dependency_job_id":"08592c86-3e18-4401-a6f1-3055ba1bdac6","html_url":"https://github.com/ncarlier/webhookd","commit_stats":{"total_commits":273,"total_committers":16,"mean_commits":17.0625,"dds":"0.10256410256410253","last_synced_commit":"0df2a5269e8f8cddef4834168d6a17b8fa458c92"},"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncarlier%2Fwebhookd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncarlier%2Fwebhookd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncarlier%2Fwebhookd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncarlier%2Fwebhookd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ncarlier","download_url":"https://codeload.github.com/ncarlier/webhookd/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248654046,"owners_count":21140235,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["api-rest","bash","cd","ci","continuous-deployment","continuous-integration","go","shell-script","webhook","webhook-server"],"created_at":"2024-08-01T13:01:15.610Z","updated_at":"2025-04-13T01:59:41.357Z","avatar_url":"https://github.com/ncarlier.png","language":"Go","readme":"# webhookd\n\n[![Build Status](https://github.com/ncarlier/webhookd/actions/workflows/build.yml/badge.svg)](https://github.com/ncarlier/webhookd/actions/workflows/build.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/ncarlier/webhookd)](https://goreportcard.com/report/github.com/ncarlier/webhookd)\n[![Docker pulls](https://img.shields.io/docker/pulls/ncarlier/webhookd.svg)](https://hub.docker.com/r/ncarlier/webhookd/)\n[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/nunux)\n\nA very simple webhook server to launch shell scripts.\n\n![Logo](webhookd.svg)\n\n## At a glance\n\n![Demo](demo.gif)\n\n## Installation\n\nRun the following command:\n\n```bash\n$ go install github.com/ncarlier/webhookd@latest\n```\n\n**Or** download the binary regarding your architecture:\n\n```bash\n$ sudo curl -s https://raw.githubusercontent.com/ncarlier/webhookd/master/install.sh | bash\nor\n$ curl -sf https://gobinaries.com/ncarlier/webhookd | sh\n```\n\n**Or** use Docker:\n\n```bash\n$ docker run -d --name=webhookd \\\n  -v ${PWD}/scripts:/scripts \\\n  -p 8080:8080 \\\n  ncarlier/webhookd\n```\n\n\u003e Note: The official Docker image is lightweight and allows to run simple scripts but for more advanced needs you can use the `ncarlier/webhookd:edge-distrib` image.\n\u003e For example, with this `distrib` image, you can interact with your Docker daemon using Docker CLI or Docker Compose.\n\n**Or** use APT:\n\nFinally, it is possible to install Webhookd using the Debian packaging system through this [custom repository](https://packages.azlux.fr/).\n\n\u003e Note: Custom configuration variables can be set into `/etc/webhookd.env` file.\n\u003e Sytemd service is already set and enable, you just have to start it with `systemctl start webhookd`.\n\n## Configuration\n\nWebhookd can be configured by using command line parameters or by setting environment variables.\n\nType `webhookd -h` to display all parameters and related environment variables.\n\nAll configuration variables are described in [etc/default/webhookd.env](./etc/default/webhookd.env) file.\n\n## Usage\n\n### Directory structure\n\nWebhooks are simple scripts within a directory structure.\n\nBy default inside the `./scripts` directory.\nYou can change the default directory using the `WHD_HOOK_SCRIPTS` environment variable or `-hook-scripts` parameter.\n\n*Example:*\n\n```\n/scripts\n|--\u003e /github\n  |--\u003e /build.sh\n  |--\u003e /deploy.sh\n|--\u003e /push.js\n|--\u003e /echo.sh\n|--\u003e ...\n```\n\n\u003e Note: Webhookd is able to run any type of file in this directory as long as the file is executable.\nFor example, you can execute a Node.js file if you give execution rights to the file and add the appropriate `#!` header (in this case: `#!/usr/bin/env node`).\n\nYou can find sample scripts in the [example folder](./scripts/examples).\nIn particular, examples of integration with Gitlab and Github.\n\n### Webhook call\n\nThe directory structure define the webhook URL.\n\nYou can omit the script extension. If you do, webhookd will search by default for a `.sh` file.\nYou can change the default extension using the `WHD_HOOK_DEFAULT_EXT` environment variable or `-hook-default-ext` parameter.\nIf the script exists, the output will be send to the HTTP response.\n\nDepending on the HTTP request, the HTTP response will be a HTTP `200` code with the script's output in real time (streaming), or the HTTP response will wait until the end of the script's execution and return the output (tuncated) of the script as well as an HTTP code relative to the script's output code.\n\nThe streaming protocol depends on the HTTP request:\n\n- [Server-sent events][sse] is used when `Accept` HTTP header is equal to `text/event-stream`.\n- [Chunked Transfer Coding][chunked] is used when `X-Hook-Mode` HTTP header is equal to `chunked`.\nIt's the default mode.\nYou can change the default mode using the `WHD_HOOK_DEFAULT_MODE` environment variable or `-hook-default-mode` parameter.\n\n[sse]: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events\n[chunked]: https://datatracker.ietf.org/doc/html/rfc2616#section-3.6.1\n\nIf no streaming protocol is needed, you must set `X-Hook-Mode` HTTP header to `buffered`.\nThe HTTP reponse will block until the script is over:\n\n- Sends script output limited to the last 100 lines. You can modify this limit via the HTTP header `X-Hook-MaxBufferedLines`.\n- Convert the script exit code to HTTP code as follow:\n  - 0: `200 OK`\n  - Between 1 and 99: `500 Internal Server Error`\n  - Between 100 and 255: Add 300 to get HTTP code between 400 and 555\n\n\u003e Remember: a process exit code is between 0 and 255. 0 means that the execution is successful.\n\n*Example:*\n\nThe script: `./scripts/foo/bar.sh`\n\n```bash\n#!/bin/bash\n\necho \"foo foo foo\"\necho \"bar bar bar\"\n\nexit 118\n```\n\nStreamed output using  `Server-sent events`:\n\n```bash\n$ curl -v --header \"Accept: text/event-stream\" -XGET http://localhost:8080/foo/bar\n\u003c HTTP/1.1 200 OK\n\u003c Content-Type: text/event-stream\n\u003c Transfer-Encoding: chunked\n\u003c X-Hook-Id: 8\n\ndata: foo foo foo\n\ndata: bar bar bar\n\nerror: exit status 118\n```\n\nStreamed output using `Chunked Transfer Coding`:\n\n```bash\n$ curl -v -XPOST --header \"X-Hook-Mode: chunked\" http://localhost:8080/foo/bar\n\u003c HTTP/1.1 200 OK\n\u003c Content-Type: text/plain; charset=utf-8\n\u003c Transfer-Encoding: chunked\n\u003c X-Hook-Id: 7\n\nfoo foo foo\nbar bar bar\nerror: exit status 118\n\n```\n\nBlocking HTTP request:\n\n```bash\n$ curl -v -XPOST --header \"X-Hook-Mode: buffered\" http://localhost:8080/foo/bar\n\u003c HTTP/1.1 418 I m a teapot\n\u003c Content-Type: text/plain; charset=utf-8\n\u003c X-Hook-Id: 9\n\nfoo foo foo\nbar bar bar\nerror: exit status 118\n```\n\n\u003e Note that in this last example the HTTP response is equal to `exit code + 300` : `418 I'm a teapot`.\n\n### Webhook parameters\n\nYou have several ways to provide parameters to your webhook script:\n\n- URL request parameters are converted to script variables\n- HTTP headers are converted to script variables\n- Request body (depending the Media Type):\n  - `application/x-www-form-urlencoded`: keys and values are converted to script variables\n  - `text/*` or `application/json`: payload is transmit to the script as first parameter.\n\n\u003e Note: Variable name follows \"snakecase\" naming convention.\nTherefore the name can be altered.\n*ex: `CONTENT-TYPE` will become `content_type`.*\n\nWebhookd adds some additional parameters to the script:\n\n- `hook_id`: hook ID (auto-increment)\n- `hook_name`: hook name\n- `hook_method`: HTTP request method\n- `x_forwarded_for`: client IP\n- `x_webauth_user`: username if authentication is enabled\n\n*Example:*\n\nThe script:\n\n```bash\n#!/bin/bash\n\necho \"Hook information: name=$hook_name, id=$hook_id, method=$hook_method\"\necho \"Query parameter: foo=$foo\"\necho \"Header parameter: user-agent=$user_agent\"\necho \"Script parameters: $1\"\n```\n\nThe result:\n\n```bash\n$ curl --data @test.json -H 'Content-Type: application/json' http://localhost:8080/echo?foo=bar\nHook information: name=echo, id=1, method=POST\nQuery parameter: foo=bar\nHeader parameter: user-agent=curl/7.52.1\nScript parameter: {\"message\": \"this is a test\"}\n```\n\n### Webhook timeout configuration\n\nBy default a webhook has a timeout of 10 seconds.\nThis timeout is globally configurable by setting the environment variable:\n`WHD_HOOK_TIMEOUT` (in seconds).\n\nYou can override this global behavior per request by setting the HTTP header:\n`X-Hook-Timeout` (in seconds).\n\n*Example:*\n\n```bash\n$ curl -H \"X-Hook-Timeout: 5\" http://localhost:8080/echo?foo=bar\n```\n\n### Webhook logs\n\nAs mentioned above, web hook logs are stream in real time during the call.\nHowever, you can retrieve the logs of a previous call by using the hook ID: `http://localhost:8080/\u003cNAME\u003e/\u003cID\u003e`\n\nThe hook ID is returned as an HTTP header with the Webhook response: `X-Hook-ID`\n\n*Example:*\n\n```bash\n$ # Call webhook\n$ curl -v http://localhost:8080/echo?foo=bar\n...\n\u003c HTTP/1.1 200 OK\n\u003c Content-Type: text/plain\n\u003c X-Hook-Id: 2\n...\n$ # Retrieve logs afterwards\n$ curl http://localhost:8080/echo/2\n```\n\nIf needed, you can also redirect hook logs to the server output (configured by the `WHD_LOG_MODULES=hook` environment variable).\n\n### Post hook notifications\n\nThe output of the script is collected and stored into a log file\n(configured by the `WHD_HOOK_LOG_DIR` environment variable).\n\nOnce the script is executed, you can send the result and this log file to a notification channel.\nCurrently, only two channels are supported: `Email` and `HTTP`.\n\nNotifications configuration can be done as follow:\n\n```bash\n$ export WHD_NOTIFICATION_URI=http://requestb.in/v9b229v9\n$ # or\n$ webhookd --notification-uri=http://requestb.in/v9b229v9\n```\n\n\u003e Note: Only the output of the script prefixed by \"notify:\" is sent to the notification channel.\nIf the output does not contain a prefixed line, no notification will be sent.\n\n**Example:**\n\n```bash\n#!/bin/bash\n\necho \"notify: Hello World\" # Will be notified\necho \"Goodbye\"             # Will not be notified\n```\n\nYou can override the notification prefix by adding `prefix` as a query parameter to the configuration URL.\n\n**Example:** http://requestb.in/v9b229v9?prefix=\"foo:\"\n\n#### HTTP notification\n\nConfiguration URI: `http://example.org`\n\nOptions (using query parameters):\n\n- `prefix`: Prefix to filter output log\n\nThe following JSON payload is POST to the target URL:\n\n```json\n{\n  \"id\": \"42\",\n  \"name\": \"echo\",\n  \"text\": \"foo\\nbar...\\n\",\n  \"error\": \"Error cause... if present\",\n}\n```\n\n\u003e Note: that because the payload have a `text` attribute, you can use a [Mattermost][mattermost], [Slack][slack] or [Discord][discord] webhook endpoint.\n\n[mattermost]: https://docs.mattermost.com/developer/webhooks-incoming.html\n[discord]: https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook\n[slack]: https://api.slack.com/messaging/webhooks\n\n#### Email notification\n\nConfiguration URI: `mailto:foo@bar.com`\n\nOptions (using query parameters):\n\n- `prefix`: Prefix to filter output log\n- `smtp`: SMTP host to use (by default: `localhost:25`)\n- `username`: SMTP username (not set by default)\n- `password`: SMTP password (not set by default)\n- `conn`: SMTP connection type (`tls`, `tls-insecure` or by default: `plain`)\n- `from`: Sender email (by default: `noreply@nunux.org`)\n- `subject`: Email subject (by default: `[whd-notification] {name}#{id} {status}`)\n\n### Authentication\n\nYou can restrict access to webhooks using HTTP basic authentication.\n\nTo activate basic authentication, you have to create a `htpasswd` file:\n\n```bash\n$ # create passwd file the user 'api'\n$ htpasswd -B -c .htpasswd api\n```\nThis command will ask for a password and store it in the htpawsswd file.\n\nBy default, the daemon will try to load the `.htpasswd` file.\nBut you can override this behavior by specifying the location of the file:\n\n```bash\n$ export WHD_PASSWD_FILE=/etc/webhookd/users.htpasswd\n$ # or\n$ webhookd --passwd-file /etc/webhookd/users.htpasswd\n```\n\nOnce configured, you must call webhooks using basic authentication:\n\n```bash\n$ curl -u api:test -XPOST \"http://localhost:8080/echo?msg=hello\"\n```\n\n### Signature\n\nYou can ensure message integrity (and authenticity) by signing HTTP requests.\n\nWebhookd supports 2 signature methods:\n\n- [HTTP Signatures](https://www.ietf.org/archive/id/draft-cavage-http-signatures-12.txt)\n- [Ed25519 Signature](https://ed25519.cr.yp.to/) (used by [Discord](https://discord.com/developers/docs/interactions/receiving-and-responding#security-and-authorization))\n\nTo activate request signature verification, you have to configure the truststore:\n\n```bash\n$ export WHD_TRUSTSTORE_FILE=/etc/webhookd/pubkey.pem\n$ # or\n$ webhookd --truststore-file /etc/webhookd/pubkey.pem\n```\n\nPublic key is stored in PEM format.\n\nOnce configured, you must call webhooks using a valid signature:\n\n```bash\n# Using HTTP Signature:\n$ curl -X POST \\\n  -H 'Date: \u003creq-date\u003e' \\\n  -H 'Signature: keyId=\u003ckey-id\u003e,algorithm=\"rsa-sha256\",headers=\"(request-target) date\",signature=\u003csignature-string\u003e' \\\n  -H 'Accept: application/json' \\\n  \"http://localhost:8080/echo?msg=hello\"\n# or using Ed25519 Signature:\n$ curl -X POST \\\n  -H 'X-Signature-Timestamp: \u003ctimestamp\u003e' \\\n  -H 'X-Signature-Ed25519: \u003csignature-string\u003e' \\\n  -H 'Accept: application/json' \\\n  \"http://localhost:8080/echo?msg=hello\"\n```\n\nYou can find a small HTTP client in the [\"tooling\" directory](./tooling/httpsig/README.md) that is capable of forging `HTTP signatures`.\n\n### TLS\n\nYou can activate TLS to secure communications:\n\n```bash\n$ export WHD_TLS_ENABLED=true\n$ # or\n$ webhookd --tls-enabled\n```\n\nBy default webhookd is expecting a certificate and key file (`./server.pem` and `./server.key`).\nYou can provide your own certificate and key with `-tls-cert-file` and `-tls-key-file`.\n\nWebhookd also support [ACME](https://ietf-wg-acme.github.io/acme/) protocol.\nYou can activate ACME by setting a fully qualified domain name:\n\n```bash\n$ export WHD_TLS_ENABLED=true\n$ export WHD_TLS_DOMAIN=hook.example.com\n$ # or\n$ webhookd --tls-enabled --tls-domain=hook.example.com\n```\n\n**Note:**\nOn *nix, if you want to listen on ports 80 and 443, don't forget to use `setcap` to privilege the binary:\n\n```bash\nsudo setcap CAP_NET_BIND_SERVICE+ep webhookd\n```\n\n## License\n\nThe MIT License (MIT)\n\nSee [LICENSE](./LICENSE) to see the full text.\n\n---\n","funding_links":["https://www.paypal.me/nunux"],"categories":["Go","开源类库","Open source library","bash","Active projects"],"sub_categories":["未归类","Not Categorized","Applications"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fncarlier%2Fwebhookd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fncarlier%2Fwebhookd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fncarlier%2Fwebhookd/lists"}