A webhook is an HTTP endpoint on your server which can be called to execute tasks. For example in the case of GitHub you can setup that GitHub sends an HTTP POST each time you do something on a specific repository. When your endpoint is called, it will execute a command like running tests, deploying a new version, sending an email, or whatever you want.
It’s been a while since I wanted to do this sort of things, without using a SaaS solution to handle the webhooks. Recently I discovered the webhook library which can do exactly what I want on my server with just a few configuration.
I’m using an Ubuntu 64-bit on my server, so let’s download the corresponding binary on the releases page. Then I must upload the binary on my server in the /var/www/webhooks
directory along with a hooks.json
file containing an empty array []
.
I want webhook to be a service on my server. To do so, as I’m using systemd, I need to create the corresponding service file webhook.service
in /etc/systemd/system
directory:
[Unit]
Description=Webhooks
[Service]
ExecStart=/var/www/webhooks/webhook -hooks /var/www/webhooks/hooks.json -hotreload
[Install]
WantedBy=multi-user.target
The -hooks
option specifies the path to my hooks file. The -hotreload
option tells to the webhook library to watch for changes in my hooks file and to reload it automatically. This option can be useful if I want to add a hook or update an existing one without restarting my service.
Then I need to run a few commands with systemctl
:
systemctl enable webhook.service
to enable the newly created servicesystemctl start webhook.service
to start the serviceNow if I check the service status using service webhooks status
command, I should get this:
● webhooks.service - Webhooks
Loaded: loaded (/etc/systemd/system/webhooks.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2017-09-02 13:07:52 CEST; 9min ago
Main PID: 30444 (webhook)
CGroup: /system.slice/webhooks.service
└─30444 /var/www/webhooks/webhook -hooks /var/www/webhooks/hooks.json -hotreload
I now have a webhook service on my server. By default it listens on 0.0.0.0:9000. But I want it to be available on a specific domain over SSL. As I’m using nginx for my other websites, I want to do the same with my webhook service. To achieve that I need to create this vhost (usually located in /etc/nginx/sites-available
):
server {
listen 443 ssl;
server_name webhooks.my-server.com;
ssl_certificate /my-certificate/my-server.com/fullchain.pem;
ssl_certificate_key /my-certificate/my-server.com/privkey.pem;
location / {
try_files $uri @proxy;
}
location @proxy {
proxy_pass http://webhooks;
}
}
upstream webhooks {
server 127.0.0.1:9000;
}
My webhook service is finally accessible from the Internet, but it doesn’t do anything yet.
The webhook library allows some configuration to:
For my first webhook, I want something simple: deploying my website each time I push a new tag. To do so, I just need to update my hooks.json
as follow:
[
{
"id": "simple-pull",
"execute-command": "/var/www/webhooks/commands/simple-pull",
"pass-arguments-to-command": [
{
"source": "payload",
"name": "repository.name"
}
],
"trigger-rule": {
"and": [
{
"match":
{
"type": "payload-hash-sha1",
"secret": "mysecret",
"parameter":
{
"source": "header",
"name": "X-Hub-Signature"
}
}
},
{
"match":
{
"type": "value",
"value": "tag",
"parameter":
{
"source": "payload",
"name": "ref_type"
}
}
}
]
}
}
]
The trigger-rule
attribute allows defining conditions to meet before my webhook is triggered. In the example above I only check if the signature from GitHub is valid and if there is a new tag created. Then the simple-pull
script is called with the repository name as an argument.
I wrote my simple-pull
script that way so I can reuse it for the other MD websites to deploy them all using a simple git pull
:
#! /bin/bash
cd /var/www/$1
git pull
Please note that this script requires the targetted repository to be already cloned in /var/www
.
The last thing to do is to activate webhooks in the repository on GitHub. To do that I open the settings tabs and go to webhooks section to set some parameters:
https://webhooks.my-server.com/hooks/simple-pull
application/json
mysecret
From now on my website will be deployed each time I push a new tag 🙂
David Authier
Développeur freelance