What we’re building
When you push code to GitHub, you want your VPS to automatically:
- Receive a notification from GitHub
- Pull the latest code
- Install dependencies
- 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:
- Go to your repository on GitHub
- Click Settings → Webhooks → Add webhook
- 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”
- Payload URL:
- 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.logfor 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.