A small Go-based webhook server for safely triggering local deployment scripts from GitHub Webhooks.
deploy-gate verifies GitHub webhook signatures and executes configured local scripts based on the request path. It is designed for environments where deployments should be triggered without exposing the Docker Socket through a webhook endpoint.
- GitHub HMAC-SHA256 signature verification
- Path-based deployment routing
- Configurable script execution
- Single binary deployment
- Uses only the Go standard library
- No Docker Socket access required by
deploy-gateitself
GitHub Webhook
│
▼
deploy-gate
│
├─ /deploy/bot → deploy-bot.sh
│
└─ /deploy/dashboard → deploy-dashboard.sh
deploy-gate is responsible for:
- Receiving webhook requests
- Verifying GitHub signatures
- Selecting a configured route
- Executing the configured script
Actual deployment logic should be implemented in the script invoked by each route.
- Linux
- GitHub Webhooks
Go is only required when building from source. Prebuilt binaries can be distributed through GitHub Releases.
deploy-gate uses environment variables and a JSON configuration file.
| Variable | Required | Description |
|---|---|---|
DEPLOY_SECRET |
Yes | GitHub Webhook secret used for signature verification |
DEPLOY_CONFIG |
Yes | Path to the JSON configuration file |
Example:
DEPLOY_SECRET=replace_me
DEPLOY_CONFIG=/etc/deploy-gate/config.jsonExample:
{
"routes": [
{
"path": "/deploy/bot",
"script": "/opt/deploy-gate/scripts/deploy-bot.sh"
},
{
"path": "/deploy/dashboard",
"script": "/opt/deploy-gate/scripts/deploy-dashboard.sh"
}
]
}Each route maps an HTTP path to a local script.
The script path must be an absolute path.
go build -o bin/deploy-gate ./cmd/deploy-gateDEPLOY_SECRET=replace_me \
DEPLOY_CONFIG=/etc/deploy-gate/config.json \
./bin/deploy-gateThe server listens on :9000 by default.
[Unit]
Description=deploy-gate
After=network.target
[Service]
Type=simple
Environment=DEPLOY_SECRET=replace_me
Environment=DEPLOY_CONFIG=/etc/deploy-gate/config.json
ExecStart=/usr/local/bin/deploy-gate
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.targetDocker can be used when the configured scripts can run inside the container.
Example:
cp compose.yml.example compose.yml
cp config.json.example config.json
echo 'DEPLOY_SECRET=replace_me' > .env
mkdir -p scriptsExample compose.yml:
services:
deploy-gate:
image: ghcr.io/t1nyb0x/deploy-gate:latest
container_name: deploy-gate
restart: unless-stopped
environment:
DEPLOY_SECRET: ${DEPLOY_SECRET}
DEPLOY_CONFIG: /etc/deploy-gate/config.json
volumes:
- ./config.json:/etc/deploy-gate/config.json:ro
- ./scripts:/scripts:ro
ports:
- "9000:9000"Example config.json:
{
"routes": [
{
"path": "/deploy/example",
"script": "/scripts/deploy-example.sh"
}
]
}deploy-gate itself does not require Docker Socket access.
If your deployment script needs to control Docker on the host, consider running deploy-gate as a host-level systemd service instead of mounting the Docker Socket into the container.
Accepts webhook requests from GitHub.
Example:
POST /deploy/bot
POST /deploy/dashboard
Signature header:
X-Hub-Signature-256: sha256=<signature>Responses:
| Status | Description |
|---|---|
| 204 | Script executed successfully |
| 403 | Invalid method or signature |
| 500 | Script execution failed |
deploy-gate/
├── cmd/
│ └── deploy-gate/
│ └── main.go
├── internal/
│ ├── config/
│ │ └── config.go
│ ├── deploy/
│ │ └── run.go
│ ├── signature/
│ │ └── hmac.go
│ └── webhook/
│ └── deploy.go
├── go.mod
└── README.md
deploy-gate does not require direct access to the Docker Socket.
Exposing the Docker Socket through a webhook endpoint effectively grants remote control over containers and, in many cases, the host system itself.
deploy-gate only verifies webhook signatures and executes explicitly configured local scripts. Keep scripts small, auditable, and restricted to the deployment actions they need to perform.
MIT License