Auto-deploy from GitHub to VPS | Webhooks Tutorial | ServerPoint Skip to main content
Linux

How to automatically build your Node.js app when you push to GitHub

By ServerPoint's Team January 15, 2026

What we’re building

When you push code to GitHub, you want your VPS to automatically:

  1. Receive a notification from GitHub
  2. Pull the latest code
  3. Install dependencies
  4. Restart your application

This is called a webhook-based deployment. GitHub sends an HTTP request to your server whenever you push, and your server runs a script to update itself.

Prerequisites

Before starting, make sure you have:

  • A VPS with Node.js installed
  • Your application already deployed and running with PM2
  • SSH access to your server
  • A GitHub repository with your code

Step 1: Install a webhook listener

We’ll use a lightweight tool called webhook to listen for GitHub notifications.

On Ubuntu:

sudo apt update
sudo apt install -y webhook

Step 2: Create a deployment script

Create a script that will run whenever GitHub sends a webhook. This script pulls your code and restarts the app.

sudo mkdir -p /opt/scripts
sudo nano /opt/scripts/deploy.sh

Add the following (adjust paths to match your setup):

#!/bin/bash

# Configuration
REPO_DIR="/home/youruser/your-app"
BRANCH="main"
LOG_FILE="/var/log/deploy.log"

echo "=== Deployment started at $(date) ===" >> $LOG_FILE

cd $REPO_DIR

# Pull latest changes
git fetch origin
git reset --hard origin/$BRANCH

# Install dependencies
npm install >> $LOG_FILE 2>&1

# Build if needed (uncomment if you have a build step)
# npm run build >> $LOG_FILE 2>&1

# Restart the application with PM2
pm2 restart your-app-name >> $LOG_FILE 2>&1

echo "=== Deployment completed at $(date) ===" >> $LOG_FILE

Make it executable:

sudo chmod +x /opt/scripts/deploy.sh

Step 3: Configure the webhook listener

Create a configuration file for the webhook tool:

sudo mkdir -p /etc/webhook
sudo nano /etc/webhook/hooks.json

Add this configuration:

[
  {
    "id": "deploy",
    "execute-command": "/opt/scripts/deploy.sh",
    "command-working-directory": "/opt/scripts",
    "response-message": "Deployment triggered",
    "trigger-rule": {
      "and": [
        {
          "match": {
            "type": "payload-hmac-sha256",
            "secret": "your-secret-here",
            "parameter": {
              "source": "header",
              "name": "X-Hub-Signature-256"
            }
          }
        },
        {
          "match": {
            "type": "value",
            "value": "refs/heads/main",
            "parameter": {
              "source": "payload",
              "name": "ref"
            }
          }
        }
      ]
    }
  }
]

Important: Replace your-secret-here with a random string. You’ll use this same secret in GitHub. Generate one with:

openssl rand -hex 32

Step 4: Create a systemd service

Create a service file so the webhook listener starts automatically:

sudo nano /etc/systemd/system/webhook.service

Add:

[Unit]
Description=Webhook listener
After=network.target

[Service]
ExecStart=/usr/bin/webhook \
  -hooks /etc/webhook/hooks.json \
  -port 9000 \
  -verbose
Restart=always
User=root

[Install]
WantedBy=multi-user.target

Enable and start the service:

sudo systemctl daemon-reload
sudo systemctl enable webhook
sudo systemctl start webhook

Step 5: Open the webhook port in your firewall

In your ServerPoint’s Client Portal, add a firewall rule to allow port 9000 (or whatever port you chose).

Only allow this port if you’re using the webhook. Keep all other unnecessary ports closed.

Step 6: Configure GitHub

Now tell GitHub to send webhooks to your server:

  1. Go to your repository on GitHub
  2. Click SettingsWebhooksAdd webhook
  3. Configure:
    • Payload URL: http://your-server-ip:9000/hooks/deploy
    • Content type: application/json
    • Secret: The same secret you put in hooks.json
    • Events: Select “Just the push event”
  4. Click Add webhook

GitHub will send a test ping. Check if it succeeded.

Step 7: Test the deployment

Make a small change to your repository and push:

git add .
git commit -m "Test automatic deployment"
git push origin main

Check your server logs:

tail -f /var/log/deploy.log

You should see the deployment script running.

Securing your webhook endpoint

A few security tips:

Use HTTPS

If you have a domain pointing to your server, set up Nginx as a reverse proxy with SSL:

sudo apt install -y nginx certbot python3-certbot-nginx

Configure Nginx to proxy requests to the webhook listener, then use Certbot to add SSL.

Restrict by IP

GitHub publishes their webhook IP addresses. You can configure your firewall to only allow webhook requests from GitHub’s IPs.

Keep the secret secure

Never commit your webhook secret to your repository. If someone knows your secret and endpoint, they could trigger deployments.

Troubleshooting

Webhook not triggering

  • Check that port 9000 is open in your firewall
  • Verify the webhook URL is correct in GitHub settings
  • Check GitHub’s webhook delivery logs for errors

Deployment script fails

  • Check /var/log/deploy.log for error messages
  • Make sure the script has execute permissions
  • Verify the paths in the script match your actual setup

Permission issues

  • The webhook service runs as root by default. For better security, create a dedicated user and adjust file permissions accordingly.

Explore our VPS plans for reliable servers to run your deployments.