If you’re running a Next.js application on an Ubuntu server, you probably want a clean workflow to update your production app every time you push to GitHub. In this guide, we’ll walk through setting up GitHub webhooks, a small server to receive them, and a deployment script that builds and restarts your app with PM2.
✅ Prerequisites
- A public or private Ubuntu server
- Node.js, npm, and PM2 installed
- A running Next.js app managed by PM2
- Your app hosted on GitHub (private or public)
- SSH access to your server
Step 1: Generate SSH Key for GitHub (if needed)
On your Ubuntu server, generate an SSH key so the server can authenticate with GitHub and pull code automatically:
ssh-keygen -t rsa -b 4096 -C "your-github-email@example.com"
Press Enter to accept the default path (~/.ssh/id_rsa
).
Now, copy the public key:
cat ~/.ssh/id_rsa.pub
Go to GitHub > Settings > SSH and GPG keys > New SSH key, and paste it in.
Test the connection:
ssh -T git@github.com
You should see a “You’ve successfully authenticated” message.
Step 2: Clone Your Repository
Pick a directory for your app and clone your GitHub repo:
cd /var/www
git clone git@github.com:your-username/your-repo.git
cd your-repo
Install dependencies and build the project:
npm install
npm run build
Start the app with PM2:
pm2 start npm --name "your-app-name" -- start
pm2 save
Step 3: Create the Deployment Script
Create a shell script that will handle updates:
nano ~/deploy.sh
Add this content:
#!/bin/bash
cd /var/www/your-repo
echo "Pulling latest changes..."
git pull origin main
echo "Installing dependencies..."
npm install
echo "Building the app..."
npm run build
echo "Restarting app with PM2..."
pm2 restart your-app-name
echo "Deployment complete!"
Make it executable:
chmod +x ~/deploy.sh
Step 4: Set Up a Webhook Listener
Create a simple Express server that listens for GitHub webhooks:
mkdir ~/webhook && cd ~/webhook
nano server.js
Paste the following code:
const express = require("express");
const { exec } = require("child_process");
const app = express();
app.use(express.json());
app.post("/webhook", (req, res) => {
const payload = req.body;
if (payload.ref === "refs/heads/main") {
console.log("Push to main detected. Starting deployment...");
exec("bash ~/deploy.sh", (err, stdout, stderr) => {
if (err) {
console.error(`Deployment error: ${err.message}`);
return res.status(500).send("Deployment failed.");
}
console.log(stdout);
console.error(stderr);
res.status(200).send("Deployment complete.");
});
} else {
res.status(200).send("Push ignored (not main branch).");
}
});
const PORT = 4000;
app.listen(PORT, () => {
console.log(`Webhook server listening on port ${PORT}`);
});
Initialize and install dependencies:
npm init -y
npm install express
Start the server using PM2:
pm2 start server.js --name webhook
pm2 save
Step 5: Open the Webhook Port (Optional)
If your firewall is active, allow the webhook port:
sudo ufw allow 4000
Step 6: Set Up GitHub Webhook
In your GitHub repo:
- Go to Settings > Webhooks > Add webhook
- Payload URL:
http://your-server-ip:4000/webhook
- Content type:
application/json
- Leave secret empty (or handle it in code if using)
- Events: Just the push event
- Save webhook
Step 7: Test the Deployment Flow
Make a small commit to the main
branch:
git add .
git commit -m "Test auto-deploy"
git push origin main
Then monitor the webhook log:
pm2 logs webhook
You should see output indicating that the deployment script was triggered, the app was rebuilt, and restarted via PM2.
What Are the Advantages of Using This Webhook Setup?
Hands-Free Deployment
Every time you push to themain
branch, your app automatically updates — no need to SSH into the server, pull manually, or restart services.Fast Feedback Loop
Code changes go live in seconds, keeping development and production in sync. This is especially useful for small teams or solo developers.No External CI/CD Needed
You don’t need to rely on tools like GitHub Actions, Jenkins, or CircleCI. Everything runs locally on your own server, which is great for simplicity and control.Customizable Deployment Logic
You have full control over the deployment process. Want to run tests, update environment variables, or notify Slack? Just add it to yourdeploy.sh
.Lightweight & Resource-Friendly
Unlike full CI/CD tools that require containers or background jobs, this setup runs with minimal overhead — just a simple Express server and PM2.Works with Private Repos
Since you're using SSH keys to authenticate with GitHub, this works equally well with private repositories.Secure by Design
You can lock down access to the webhook port, use GitHub IP whitelisting, and add secret token verification for even more security.Great for VPS and Self-Hosted Environments
Whether you're using DigitalOcean, Hetzner, Linode, or your own machine, this approach is ideal for traditional Ubuntu-based deployments.
'Web Development' 카테고리의 다른 글
Fixing JS and CSS Not Loading in Next.js on GitHub Pages (0) | 2025.04.10 |
---|