How to Render Automated Application Deployment with GitHub Webhooks, Nginx, Debian, Hestia CP – A DIY Guide

December 3, 2023 (1y ago)

In the fast-paced world of software development, staying ahead often means automating repetitive tasks. One such task that has become critical is the deployment of applications.
Services like Render.com have gained popularity for simplifying the deployment process — but what if you could build your own auto-deploy system?

That's exactly what I set out to do at 9 PM one night — and by 1 AM, a fully working prototype was up and running.


thumbnail

🧠 The Thought

I wanted to replicate one powerful Render.com feature: automatic deployments when a pull request is made. This meant setting up a flow where:

Let’s break it down.


🧩 The Problem

Our goal:
When a pull request is made → a subdomain like feature-xyz.domain.com is created and the app is deployed live.

To do this, we need:

  1. ✅ Wildcard DNS setup
  2. ✅ GitHub webhook configuration
  3. ✅ Server webhook listener + shell script
  4. ✅ Nginx + HestiaCP setup
  5. ✅ Secure deployment and SSL

🌍 Setting Up DNS Records

Test it: Visit test.domain.com in a browser — it should resolve to your server. This step is crucial for dynamic subdomain deployments.


🔗 Configuring GitHub Webhooks

  1. Go to your repo → Settings → Webhooks → Add webhook
  2. Set the payload URL to your server
  3. Select application/json and enable the Pull Request event
  4. Save

This will now send webhook data to your server anytime a PR is opened.


🛠️ Server Configuration & Script

You’ll need a webhook listener (like adnanh/webhook) configured to trigger a deployment script:

JSON configuration:
[
  {
    "id": "github-webhook",
    "execute-command": "./webhookscript.sh",
    "command-working-directory": ".",
    "response-message": "Webhook received and processing...",
    "pass-arguments-to-command": [
      {
        "source": "payload",
        "name": "action"
      },
      {
        "source": "entire-payload"
      }
    ]
  }
]

## ⚙️ webhookscript.sh

#!/bin/bash

if [ "$1" == "opened" ]; then
    action=$(echo "$2" | jq -r '.action')
    pull_request_title=$(echo "$2" | jq -r '.pull_request.title')
    pull_request_url=$(echo "$2" | jq -r '.pull_request.html_url')
    sender_login=$(echo "$2" | jq -r '.sender.login')
    clone_url=$(echo "$2" | jq -r '.repository.ssh_url')

    if [ -z "$action" ] || [ -z "$pull_request_title" ] || [ -z "$pull_request_url" ] || [ -z "$sender_login" ]; then
        echo "Error: Required fields are missing or empty in the payload."
        exit 1
    fi

    prname="${pull_request_title// /}"
    prname="${prname}.domain.com"
    alias="www.$prname"

    v-add-web-domain server $prname ipv4 yes $alias
    v-add-letsencrypt-domain server $prname $alias no
    v-add-web-domain-ssl server $prname /home/server/conf/web/$prname
    v-add-web-domain-ssl-force server $prname

    web_directory="/home/server/web/$prname/public_html"
    cd $web_directory

    if [ ! -d "$web_directory/repo_name" ]; then
        git clone "$clone_url"
    fi

    cd repo_name/app
    cp -r ~/.env $web_directory
    npm install
    npm run build
    mv -vf dist/* ../../
fi

🧭 Final Thoughts

We covered:


At 1 AM, exhausted but proud, I looked at the live PR preview link and smiled.
This is what it means to build something end to end. 💻


Wishing you productive coding and seamless deployments! 🚀
Follow me on GitHub for more DIY infra experiments and DevOps setups.

#DevOps #GitHubWebhooks #HestiaCP #Nginx #SelfHosting #Rustacean #Automation #PRDeployments