github-deploy-inator: Remote deployment triggered by GitHub webhooks

Another DevOps tool to fix your life with


4 min read

Original article at

Do you have an application hosted on a VPS? In that case, every time you push your code to version control, you will have to somehow make the server pull it and restart the process. Now, you could do it the Chimp way, which is SSH'ing in every time and running the necessary commands yourself. Or, you can automate it!

A week or two ago, I had the realization that I don't necessarily need to SSH in and run the deploy script every time I push my changes to GitHub if I could somehow automate it. That is when my search for a simple solution to this problem began.

My first stop was the post-receive git hook, but it never worked for me. I read a lot of articles on it and tried various times, but the script simply never ran.

Next, I tried the git-hooks plugin for pm2 (the process manager I knew). That, however, also didn't work and mentioned non-existent file conflicts.

At this juncture, I could have tried a CD service like Jenkins or Travis, but I decided to write my own solution instead. This aims to be easy to set up and run, and provide a lot of flexibility. Being my first proper project in Go, I also learned a lot of things along the way.

How it works

github-deploy-inator starts a web server on the specified path which listens for webhooks from GitHub. When a webhook (or any POST request in general) is received, it gets the required information and runs a command specified in a specified directory.

The config.json

All the required information is specified in a config.json file, which should be present alongside the executable. You can check out its format here.

Basic structure:

the config must contain fields for port, endpoint and listeners.

An example:

  "port": ":80",
  "endpoint": "/github/webhook",
  "listeners": [
      "name": "example-listener",
      "repository": "DeathVenom54/github-deploy-inator",
      "directory": "/home/dv/projects/docs-website",
      "command": "yarn deploy",
      "notifyDiscord": true,
      "discord": {
        "webhook": "webhook-goes-here",
        "notifyBeforeRun": true,
        "sendOutput": true
The port should start with a colon. Example: ":8080"

Setting it up

Installation and configuration

To get started, grab a release from here. If you are on a VPS, you can download it using curl. Copy the link for your OS and architecture and run this:

curl -L [release link] > && unzip

Image description

This will unzip the executable, as well as an example config file. Edit the config as per your requirements, and test it by running the executable.


This will load and verify the config. If something is wrong, it will exit. If you see the message "Listening for Github webhooks on port :PORT", the config is valid.

Note that this does not verify if the provided Discord webhook url is valid or not, so take care of it.

Run it

You will need to use a process manager to run the executable, and restart if it fails. You could use systemd, but I prefer to use pm2 as I find it simpler to use.

An Example

Let's host a simple API using this!

First of all, I cloned a super simple express API (written in Typescript).

$ git clone
$ yarn build

I used pm2 to run this API.

yarn build
pm2 start dist/main.js --name example-api

pm2 list

Now, to set up the deployer...

Assuming that you have already downloaded the correct build, let's edit the config. Here is what I ended up with:

  "port": ":80",
  "endpoint": "/webhook/github",
  "listeners": [
      "name": "my-api",
      "repository": "DeathVenom54/example-node-api",
      "directory": "/home/dv/projects",
      "command": "curl localhost:80",
      "notifyDiscord": true,
      "discord": {
        "webhook": "",
        "notifyBeforeRun": true,
        "sendOutput": true

Port 80 is a privileged port, which represents HTTP. To run this code, run this command first: sudo setcap CAP_NET_BIND_SERVICE=+eip /path/to/binary

To check if the config is valid, run the executable once.

Image description

Great! Now let's set it up with pm2

pm2 start ./github_deploy-inator_linux_x64 --name deployer

This should have it running, let's check the logs to verify

pm2 logs deployer

pm2 logs for deployer

Perfect! The last step is to add a webhook to your repository. Make sure the Content-Type is application/json. You should also set a secret, and specify it in the config.

The deployer might throw an error when GitHub sends a ping webhook once you set it up. You should ignore the error.

Now let's push something and try... It works!

2022/03/24 04:45:51 Successfully executed webhook from DeathVenom54/example-node-api

Discord notification

Next steps

If you face any bugs or difficulty while using this program, or have a suggestion for it, feel free to open an issue on Github, or let me know on my Discord server.

Happy devving!