A containerized webhook system for automated CI/CD deployments based on the adnanh/webhook server.
This tool provides a complete Docker-based solution for automated deployment of Git repositories via webhooks. It uses Traefik as a reverse proxy and supports SSL termination with Let's Encrypt.
- 🐳 Fully containerized using Docker and Docker Compose
- 🔒 Secure webhook authentication via API keys
- 📊 Deployment status tracking
- 📝 Detailed logs for each deployment
- 🔄 Automatic Git updates with configurable branches
- 🚀 Traefik integration with SSL support
- ⚙️ Template-based configuration for multiple environments
ci-webhooks/
├── docker-compose.yml # Main configuration
├── Dockerfile # Webhook server container
├── entrypoint.sh # Container entrypoint script
├── start.sh # Startup script
├── ci/
│ ├── hooks.tpl.json # Webhook configuration template
│ ├── deploy.sh # Deployment starter script
│ ├── _deploy.sh # Actual deployment worker
│ └── status.sh # Status checker
├── config/
│ ├── environment.tpl.json # Environment variables template
│ └── repos.tpl.json # Repository configuration template
└── startup/
├── Dockerfile # Init container for configuration
└── generate_env.sh # .env file generator- Docker & Docker Compose
- Running Traefik reverse proxy
- Git repository with SSH access
git clone git@github.com:temmiland/ci-webhooks.git ci-webhooks
cd ci-webhooksCopy and edit the template files:
cp config/environment.tpl.json config/environment.json
cp config/repos.tpl.json config/repos.jsonEdit config/environment.json:
{
"network": "proxy",
"ci_port": 9001,
"ci_domain": "ci.yourdomain.com",
"projects_root": "/srv/projects",
"main_webhook_dir": "/srv/ci-main",
"ci_key": "null"
}If ci_key is null, it will be generated automatically.
Edit config/repos.json:
{
"repos": [
{
"name": "my-app",
"path": "/srv/projects/my-app",
"branch": "main",
"deploy_script": "deploy.sh"
},
{
"name": "api-backend",
"path": "/srv/projects/api-backend",
"branch": "production",
"deploy_script": "scripts/deploy.sh"
}
]
}Ensure SSH keys for Git access are available and mounted into the container:
# SSH keys should be available at:
~/.ssh/id_rsa
~/.ssh/id_rsa.pub
~/.gitconfig./start.shThe system provides two main endpoints:
POST https://ci.yourdomain.com/hooks/deploy-project?key=YOUR_CI_KEY&repo=REPO_NAME
GET https://ci.yourdomain.com/hooks/status-project?key=YOUR_CI_KEY&repo=REPO_NAME
Each repository to be automatically updated requires a deployment script:
#!/bin/bash
# deploy.sh
echo "Starting deployment..."
# Install dependencies
npm install --production
# Build application
npm run build
# Restart services
docker-compose down
docker-compose up -d
echo "Deployment completed successfully"Make the script executable:
chmod +x deploy.shThe path can be defined in the deploy_script property in repos.json. Use a relative path from the repo root.
| Variable | Description | Example |
|---|---|---|
CI_DOMAIN |
Domain for webhook server | ci.example.com |
CI_PORT |
Port for webhook server | 9001 |
CI_KEY |
Authentication key | secret-key-123 |
PROJECTS_ROOT |
Path to projects | /srv/projects |
MAIN_WEBHOOK_DIR |
Path to webhook directory | /srv/projects/main-webhook |
TRAEFIK_NETWORK_NAME |
Traefik network | proxy |
curl -X POST "https://ci.yourdomain.com/hooks/deploy-project?key=YOUR_CI_KEY&repo=my-app"name: Deploy via Webhook
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Trigger deployment
run: |
DEPLOY_RESPONSE=$(curl -s -X POST "https://ci.yourdomain.com/hooks/deploy-project?key=${{ secrets.CI_KEY }}&repo=my-app")
echo "Deploy response: $DEPLOY_RESPONSE"
- name: Wait for deployment status
run: |
MAX_RETRIES=60
SLEEP=5
COUNT=0
while true; do
STATUS_RESPONSE=$(curl -s -X GET "https://ci.yourdomain.com/hooks/status-project?key=${{ secrets.CI_KEY }}&repo=my-app")
if echo "$STATUS_RESPONSE" | jq empty >/dev/null 2>&1; then
STATUS=$(echo "$STATUS_RESPONSE" | jq -r '.status')
echo "Status: $STATUS_RESPONSE"
else
echo "⚠️ $STATUS_RESPONSE"
STATUS="unknown"
fi
if [[ "$STATUS" == "success" ]]; then
echo "✅ Deployment successful!"
exit 0
elif [[ "$STATUS" == "error" || "$STATUS" == "failed" ]]; then
echo "❌ Deployment failed!"
exit 1
fi
COUNT=$((COUNT+1))
if [[ $COUNT -ge $MAX_RETRIES ]]; then
echo "⏱ Timeout: Deployment took too long."
exit 1
fi
sleep $SLEEP
doneDeployment started:
{
"status": "started",
"message": "Deployment started for my-app"
}Deployment running:
{
"status": "running",
"message": "Deployment is running"
}Deployment successful:
{
"status": "success",
"message": "Deployment successful"
}Deployment failed:
{
"status": "error",
"message": "Deployment failed"
}# Container logs
docker logs ci-web
# Deployment logs per repository
docker exec ci-web cat /opt/webhook/logs/deploy_my-app.log
# List all deployment logs
docker exec ci-web ls -la /opt/webhook/logs/{"status":"error","message":"Repo my-app not found in repos.json"}Solution: Check config/repos.json and ensure the repository is configured.
Deployment script deploy.sh not found or not executableSolution:
chmod +x /path/to/repo/deploy.shSolution: Check SSH keys and Git configuration:
ssh -T git@github.com
git config --listSolution: Check Traefik labels in docker-compose.yml and ensure the proxy network exists.
# Webhook server logs
docker logs -f ci-web
# Deployment status
docker exec ci-web find /opt/webhook/status -name "*.json" -exec cat {} \;
# Deployment logs
docker exec ci-web find /opt/webhook/logs -name "*.log" -exec tail -n 20 {} \;- Use strong CI keys:
openssl rand -hex 32- Keep containers updated:
docker compose pull
docker compose up -d- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see LICENSE.md for details.
- adnanh/webhook for the awesome webhook server
- Traefik for the reverse proxy
- Docker Community for the container ecosystem
If you like this project and want to support it:
- ⭐ Star it on GitHub
- 🔄 Share it with friends or colleagues
- 🐞 Report issues or suggest features
- 💡 Contribute code or improvements
