CI/CD with Webhook
This guide explains how to set up webhook for ShinyProxy. We assume ShinyProxy is running on DigitalOcean droplet with Ubuntu 20.04 (LTS).
Port for webhook
UFW is an Uncomplicated Firewall. We enables the UFW firewall to allow only SSH, HTTP and HTTPS. See a detailed tutorial here. Settings we did previously are commented out, uncomment as needed.
Finally, enable these rules by running sudo ufw enable.
Check ufw status.
Install webhook
We are going to use webhook.
The community maintained sudo apt-get install webhook gives a really outdated version.
Therefore we pick the latest (2.7.0) using pre-compiled binary for our
architecture (if in doubt, check dpkg --print-architecture):
Next we will follow this guide
and we move the binary and other files with settings in the /var/www/webhooks directory:
Hook definitions
Create the file hooks.json to store the hook definitions:
The following array of hook definitions goes inside (vim /var/www/webhooks/hooks.json):
Update all images
This array contains 3 hooks. The 1st and the second is
set up to work with GitLab CI/CD pipelines.
See corresponding .gitlab-ci.yml file here (check parts that are commented out in the YAML file).
These need a secret header (value "secret_token_1234")
that is used in the hook definition and in the webhook request. Change to some random
high entropy value.
The 1st hook definition calls the command webhook-pull-all-gitlab without arguments.
The command pulls the latest version of all the docker images that are on the server.
After that, it cleans up the dangling images. So let's put this command into
the /bin folder and make it executable:
This is the content that goes inside the file:
docker login might be needed when using private registries.
GitLab registry
The second hook definition uses the command webhook-pull-one-gitlab which
pulls a single image based on the argument passed.
The content of the file:
Docker Hub
The 3rd hook definition is similar the previous hook in that it also pulls a single docker image. But this one is written for the payload that Docker Hub's webhook delivers (read more here).
The image name and the tag are parsed separately, so the webhook-pull-one-dockerhub
takes these two arguments:
Webhook service
Now create the webhook.service file with the daemon settings via systemctl:
Put these into the service file (vim /etc/systemd/system/webhook.service):
The option -hotreload watches for changes in the hook.json file and reloads them upon change.
Run a few commands with systemctl:
sudo systemctl enable webhook.service to enable the newly created service,
sudo systemctl start webhook.service to start the service.
Now check the service status using sudo service webhook status. If all went well,
you should see something like:
Enabling HTTPS
Add -secure flag to watch over https. This requires also passing the certificate:
check name of certificate and private key in the dir /etc/letsencrypt/live/example.com/,
the add -secure -cert /etc/letsencrypt/live/test.side-r.com/cert.pem -key /etc/letsencrypt/live/test.side-r.com/privkey.pem to the /etc/systemd/system/webhook.service service file.
Use private key (privkey.pem) and fullchain.pem which is concatenation of the public key
(cert.pem) and the certificate chain (chain.pem).
Use crontab -e and add the line 0 2 * * * systemctl restart webhook.service:
we need to restart the webhook daemon regularly (daily in this case)
because it is not updating when the TLS certificate is renewed.
Testing with curl
Test it in -verbose mode: change example.com to your domain.
Have to open up another port, here 9001, because 9000 is taken by the daemon:
/var/www/webhooks/webhook -hooks /var/www/webhooks/hooks.json -hotreload -verbose -secure -cert /etc/letsencrypt/live/test.side-r.com/fullchain.pem -key /etc/letsencrypt/live/test.side-r.com/privkey.pem -port 9001
See more parameter settings here.
Note: we are testing over port 9001, but the real webhook is listening on port 9000.
GitLab
We use curl -i to get the response headers: 200 is what we want. Make sure to use http
protocol (and not https) if SSL certificate is not set up and used.
Using form data (url encoded, default header "Content-Type: application/x-www-form-urlencoded"):
Need to declare content-type header, payload is treated as form data by curl:
Docker Hub
This is how the simplified Docker Hub payload looks like, we can use it to get the image name and the tag:
Set webhook url as https://YOUR_IP_OR_DOMAIN:9000/hooks/pull-one-dockerhub.
Wrapping up
At the end of all this, we have the full CI/CD experience over HTTPS:

Contact us!
Would you like to run your own ShinyProxy server with CICD pipelines? Reach out to Analythium if you need commercial support and consulting services!
