Software & Configuration
Automatic Deploy with Git
How to configure automatic deployment on VPS via git push, GitHub/GitLab webhook or CI/CD
Automate your application deployment: every git push automatically updates the server without manual SSH connections.
Method 1: Git bare repository + hook (simple, no external tools)
On server: create the bare repository
# Create the bare repo (receives pushes)
mkdir -p /opt/repos/mysite.git
cd /opt/repos/mysite.git
git init --bare
# Create the post-receive hook
nano hooks/post-receive#!/bin/bash
# /opt/repos/mysite.git/hooks/post-receive
TARGET="/var/www/mysite"
GIT_DIR="/opt/repos/mysite.git"
BRANCH="main"
while read oldrev newrev ref; do
BRANCH_NAME=$(echo $ref | cut -d/ -f3)
if [ "$BRANCH_NAME" = "$BRANCH" ]; then
echo "--- Deploying branch $BRANCH ---"
git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f $BRANCH
# Post-deploy commands (adapt to your stack)
cd $TARGET
# Node.js
# npm install --production
# pm2 restart mysite
# PHP/Composer
# composer install --no-dev --optimize-autoloader
# Python
# pip install -r requirements.txt
# systemctl restart gunicorn-mysite
echo "--- Deploy completed ---"
fi
donechmod +x /opt/repos/mysite.git/hooks/post-receive
mkdir -p /var/www/mysiteOn local PC: add the remote
# Add the server as "production" remote
git remote add production ssh://root@185.100.xxx.xxx/opt/repos/mysite.git
# Deploy: push to the server
git push production mainMethod 2: GitHub/GitLab Webhook (recommended for teams)
Install a webhook server
# With webhook (lightweight Go tool)
sudo apt install webhook -y
# Or install from GitHub
wget https://github.com/adnanh/webhook/releases/latest/download/webhook-linux-amd64.tar.gz
tar -xzf webhook-linux-amd64.tar.gz
sudo mv webhook-linux-amd64/webhook /usr/local/bin/Create the deploy script
sudo nano /opt/deploy/deploy-mysite.sh#!/bin/bash
cd /var/www/mysite
git pull origin main
npm install --production
pm2 restart mysite
echo "Deploy completed: $(date)"chmod +x /opt/deploy/deploy-mysite.shConfigure webhooks
sudo nano /etc/webhook/hooks.json[
{
"id": "deploy-mysite",
"execute-command": "/opt/deploy/deploy-mysite.sh",
"command-working-directory": "/var/www/mysite",
"pass-arguments-to-command": [],
"trigger-rule": {
"match": {
"type": "payload-hmac-sha256",
"secret": "shared-secret-with-github",
"parameter": {
"source": "header",
"name": "X-Hub-Signature-256"
}
}
}
}
]# Start webhook on port 9000
webhook -hooks /etc/webhook/hooks.json -port 9000 -verbose &
# Or as a systemd service
sudo nano /etc/systemd/system/webhook.service[Unit]
Description=Webhook Deploy Service
After=network.target
[Service]
ExecStart=/usr/local/bin/webhook -hooks /etc/webhook/hooks.json -port 9000
Restart=always
User=www-data
[Install]
WantedBy=multi-user.targetsudo systemctl enable webhook && sudo systemctl start webhookConfigure GitHub
- Go to repository GitHub → Settings → Webhooks → Add webhook
- Payload URL:
http://your-server:9000/hooks/deploy-mysite - Content type:
application/json - Secret: the same
shared-secret-with-github - Event: Just the push event
Method 3: GitHub Actions with SSH
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/mysite
git pull origin main
npm install --production
pm2 restart mysiteIn GitHub Secrets add:
SERVER_HOST: server IPSERVER_USER: SSH user (e.g.root)SSH_PRIVATE_KEY: content of~/.ssh/id_rsa(private key)
Method 4: rsync + CI (for static files)
# GitHub Actions: deploy static site
- name: Build
run: npm run build
- name: Deploy with rsync
uses: burnett01/rsync-deployments@6.0.0
with:
switches: -avzr --delete
path: dist/
remote_path: /var/www/mysite/
remote_host: ${{ secrets.SERVER_HOST }}
remote_user: root
remote_key: ${{ secrets.SSH_PRIVATE_KEY }}Zero-downtime deploy with PM2
# Instead of pm2 restart (causes brief downtime):
pm2 reload mysite --update-envQuick rollback
With the git bare method:
# On server: return to previous commit
cd /var/www/mysite
git log --oneline -5
git checkout <old-commit-hash> .
pm2 restart mysite