GitHub Webhooks For Automatic Deployment

Automatically deploy to prod every time we push a change to the main branch.

GitHub Webhooks For Automatic Deployment

When working on our codebase, we want to automate deployment to save ourselves the trouble of manually doing it every time. In the last class, Mr. Lera taught us how to setup an Nginx server with Digital Ocean—I'll go over this in detail in a later article where we will make live changes to fix an issue. But for now, let's make some webhooks!

About webhooks - GitHub Docs
Learn the basics of how webhooks work to help you build and set up integrations.

Configuring Nginx

As I'm reading the docs on how to make webhooks, it turns out we'll need to make some changes to our Nginx server anyways. Let's ssh into our server with

ssh gunnhigh@gunnhigh.school

Then we want to edit the Nginx config file by entering:

sudo nano /etc/nginx/sites-available/gunnhigh.school

# or if you like vim
sudo vim /etc/nginx/sites-available/gunnhigh.school

Following the GitHub Webhook tutorial, I added the following line

This will forward any requests for api.gunnhigh.school/hooks/ to localhost:9000. With this change, let's save our file, and test to make sure the server still works. Run this command to check for typos, etc:

sudo nginx -t
Expected output

And then let's restart the nginx server to apply our changes

sudo systemctl restart nginx

GitHub Webhook Settings

With all this, let's go to our GitHub repository to enable webhooks. In the settings page, click on "Webhooks" and add a new webhook. Let's also type in our new payload url that we setup.

We want to add a secret for security, so let's generate one in the terminal by entering. Note: Ruby is not installed by default, so either find some other way to generate the secret or install ruby on your local computer

# As suggested by GitHub
ruby -rsecurerandom -e 'puts SecureRandom.hex(20)'

Obviously I won't show you the output, silly! Now let's enter our secret in and save the settings.

Handle Webhooks on Server

We'll use systemd to manage and restart our nextjs process. Let's create a config file for this.

sudo vim /lib/systemd/system/alumni-nextjs.service

And enter the following

[Unit]
After=network.target

[Service]
Type=simple
WorkingDirectory=/home/gunnhigh/gunn-alumni
ExecStart=/home/gunnhigh/gunn-alumni/scripts/deploy.sh
Restart=on-failure

[Install]
WantedBy=multi-user.target
alumni-nextjs.service

Save the file and restart the system-ctl daemon with the following

sudo systemctl daemon-reload

Let's install install the webhook package on our server

sudo apt install webhook

When complete, let's create a bash script to be run whenever our webhook triggers

vim ~/hooks/redeploy_prod.sh

# Update file permissions after you save the file
sudo chmod +x ~/hooks/redeploy_prod.sh
#!/bin/bash

/usr/bin/bash /home/gunnhigh/gunn-alumni/scripts/deploy.sh
~/hooks/redeploy_prod.sh

When complete, let's create a hooks.json in our home folder. We will use this to configure our webhook endpoints.

vim ~/hooks/hooks.json

I will be using the following configuration. Make sure to edit the value for the secret. You can refer to this link to see all the options https://github.com/adnanh/webhook/blob/master/docs/Hook-Definition.md

[
  {
    "id": "alumni-nextjs",
    "execute-command": "/home/gunnhigh/hooks/redeploy_prod.sh",
    "command-working-directory": "/home/gunnhigh/hooks",
    "trigger-rule": {
      "and": [
        {
          "match": {
            "type": "payload-hash-sha1",
            "secret": "github secret here",
            "parameter": {
              "source": "header",
              "name": "X-Hub-Signature"
            }
          }
        },
        {
          "match": {
            "type": "value",
            "value": "refs/heads/main",
            "parameter": {
              "source": "payload",
              "name": "ref"
            }
          }
        }
      ]
    }
  }
]
~/hooks/hooks.json

Save the file, and let's now make a systemd service entry for our webhook command so we can restart it easily later on.

sudo vim /lib/systemd/system/webhook.service

Looks like one already exists for me, but let's edit the file so it references our newly created hooks.json file

[Unit]
Description=Small server for creating HTTP endpoints (hooks)
Documentation=https://github.com/adnanh/webhook/

[Service]
WorkingDirectory=/home/gunnhigh/hooks
ExecStart=/usr/bin/webhook -nopanic -hooks /home/gunnhigh/hooks/hooks.json

[Install]
WantedBy=multi-user.target

To test our hooks let's open up a new screen called "hooks" and then start the webhook service.

screen -S hooks
sudo systemctl daemon-reload
sudo systemctl restart webhook

Side Note

Let's GOOOOOOOOO it worked after like 4 hours of trying to fix things!!!!! I updated the guide so everything should be fixed now

So now when you push to main, the server will automatically redeploy. But what if you want generate a preview url for each pull request so that you can easily review it? In the next article, I will be exploring how we can do that with pm2 and webhooks.