webhook
webhook is a small, configurable tool that allows creating HTTP endpoints (hooks) on in your uberspace. When triggered, these webhooks can then be used to execute different commands. You can also pass data from the HTTP request (headers, payload or query variables) to your commands. Furthermore, you can also set up specific rules that need to be met before a hook will trigger. Overall, this can enable your uberspace to integrate with a wide set of external services, for example for triggering deploys as part of a continuous integration/deployment pipeline. Webhook is written in Go.
Note
For this guide you should be familiar with the basic concepts of
domains (optional, if you want to setup a domain/subdomain)
License
All relevant legal information can be found here
Prerequisites
Your URL needs to be setup:
[isabell@stardust ~]$ uberspace web domain list
isabell.uber.space
[isabell@stardust ~]$
Installation
Download
The easiest way to setup webhook is to build it from the project’s Git repository. Clone from GitHub and change into the folder:
[isabell@stardust ~]$ git clone https://github.com/adnanh/webhook.git
[isabell@stardust ~]$ cd webhook
Install dependencies and build
Now install the required Go dependencies and build webhook using the following commands
[isabell@stardust webhook]$ go mod tidy
[isabell@stardust webhook]$ go build
Following this you will have a compiled version of webhook ready to go in ~/webhook/webhook
Writing a first webhook
Webhook can be configured using both YAML and JSON files. It also offers a wide range of options that you can find in the webhook documentation. To get started, we create a simple demo webhook using a YAML file.
Using a text editor of your choice create the file ~/webhook/hooks.yaml
and enter the following to get started:
- id: test-hook
execute-command: /home/isabell/hook-triggered.sh
command-working-directory: /home/isabell
response-message: the test-hook was triggered!
The id
will be the endpoint at which the webhook will be listening, while execute-command
specifies which command will be run when the hook is triggered, for testing this can just be a simple print-statement, e.g. you could have your hook-triggered.sh
be as simple as the below to get started.
Using a text editor of your choice, create the file ~/hook-triggered.sh
and enter the following to get started:
#!/bin/env bash
echo "This command was triggered by the webhook"
After saving it, make it executable using chmod 755 ~/hook-triggered.sh
Configuration
With webhook installed and a first hook written, we now need to setup a service for webhook to run automatically.
Creating a service
We can create a file ~/etc/services.d/webhook.ini
with the following content (adapt the values to your own directories if you have adapted them!):
[program:webhook]
directory=%(ENV_HOME)s/webhook
command=/home/isabell/webhook/webhook -hooks hooks.yaml -logfile %(ENV_HOME)s/logs/webhook.log -hotreload
startsecs=15
The -hotreload
parameter will automatically reload your hook-definitions whenever you edit them. This config will also write a logfile with the outputs in ~/logs/webhook.log
.
After creating the configuration, tell supervisord to refresh its configuration and start the service:
[isabell@stardust ~]$ supervisorctl reread
SERVICE: available
[isabell@stardust ~]$ supervisorctl update
SERVICE: added process group
[isabell@stardust ~]$ supervisorctl status
SERVICE RUNNING pid 26020, uptime 0:03:14
[isabell@stardust ~]$
Optional: Adding a (sub)domain
If you want to use a custom domain or a sub-domain, set it up now, e.g. using
[isabell@stardust ~]$ uberspace web domain add webhook.isabell.uber.space
Configuring the Web Backend
To make the application accessible from the outside, configure a web backend:
[isabell@stardust ~]$ uberspace web backend set / --http --port <port>
Set backend for / to port <port>; please make sure something is listening!
You can always check the status of your backend using "uberspace web backend list".
[isabell@stardust ~]$
By default, webhook listens on port 9000, if you have setup a sub-domain, the command to start the backend could look like this:
[isabell@stardust ~]$ uberspace web backend set webhook.isabell.uber.space --http --port 9000
Testing your first webhook
By now, webhook is running and waiting to be triggered. In this example, your test-hook would be listening at https://webhook.isabell.uber.space/hooks/test-hook
. You can try using curl from your host machine (or your uber space):
[your@host ~]$ curl https://webhook.isabell.uber.space/hooks/test-hook
On your uberspace you should then see the following in your ~/logs/webhook.log
:
[isabell@stardust ~]$ cat ~/logs/webhook.log
[webhook] 2024/09/06 18:26:31 [1e48aa] incoming HTTP GET request from [ip]:xxxx
[webhook] 2024/09/06 18:26:31 [1e48aa] test-hook got matched
[webhook] 2024/09/06 18:36:50 [9fbc68] test-hook hook triggered successfully
[webhook] 2024/09/06 18:36:50 [9fbc68] 200 | 18 B | 312.198µs | webhook.isabell.uber.space | GET /hooks/test-hook
[webhook] 2024/09/06 18:36:50 [9fbc68] executing /home/isabell/hook-triggered.sh (/home/isabell/hook-triggered.sh) with arguments ["/home/isabell/hook-triggered.sh"] and environment [] using /home/isabell as cwd
[webhook] 2024/09/06 18:37:09 [9fbc68] command output: This command was triggered by the hook
[webhook] 2024/09/06 18:37:09 [9fbc68] finished handling test-hook
Congratulations, you now ran your first webhook on your uberspace!
Securing your webhook
The example above allows anyone with knowledge of your webhook URL to trigger the specified action on your uberspace. To avoid this and make your webhook more secure, you should require the additional sending of secret information.
For example, you can require a secret token to be sent over as part of the trigger for the webhook, like this:
- id: test-hook
execute-command: /home/isabell/hook-triggered.sh
command-working-directory: /home/isabell
response-message: the test-hook was triggered!
trigger-rule:
and:
- match:
type: value
value: <secretkey>
parameter:
source: payload
name: secret_hook_token
Warning
Replace <secretkey>
with a random sequence of characters! You can create one for your own hook by running pwgen 32 1
.
With this configuration, you will have to send over a JSON payload to your test-hook
that contains secret_hook_token
as value and the right <secretkey>
as value. Using curl you can run it like this:
[your@host ~]$ curl -X POST https://webhook.isabell.uber.space/hooks/deploy-api \
-H "Content-Type: application/json" \
-d '{"secret_hook_token": "<secretkey>"}'
If you provide the correct secret, the hook will normally, as seen in the logs:
[isabell@stardust ~]$ cat ~/logs/webhook.log
[webhook] 2024/09/06 18:36:50 [9fbc68] incoming HTTP POST request from [IP]:xxxx
[webhook] 2024/09/06 18:36:50 [9fbc68] test-hook got matched
[webhook] 2024/09/06 18:36:50 [9fbc68] test-hook hook triggered successfully
Otherwise, you will see an error message in the logs:
[isabell@stardust ~]$ cat ~/logs/webhook.log
[webhook] 2024/09/06 18:36:14 [7f70d8] incoming HTTP POST request from [IP]:xxxx
[webhook] 2024/09/06 18:36:14 [7f70d8] test-hook got matched
[webhook] 2024/09/06 18:36:14 [7f70d8] test-hook got matched, but didn't get triggered because the trigger rules were not satisfied
You can check out the webhook “hook-rules” documentation for more details on how to secure your webhooks.
Tested with go1.23.0 linux/amd64, Uberspace 7.15
Written by: Bastian Greshake Tzovaras <bgreshake@googlemail.com>