- Makefile 46%
- Shell 32.5%
- Dockerfile 21.5%
Lightweight Docker container that listens for Forgejo/Gitea push webhooks and automatically rebuilds a Hugo site. Single container replacement for CI runners + Docker-in-Docker. |
||
|---|---|---|
| .env.example | ||
| .gitignore | ||
| docker-compose.yml.example | ||
| Dockerfile | ||
| entrypoint.sh | ||
| hooks.json.tmpl | ||
| Makefile | ||
| README.md | ||
| rebuild.sh | ||
| ssh_config | ||
| VERSION | ||
hugo-webhook-deployer
A lightweight Docker container that listens for Forgejo/Gitea push webhooks and automatically rebuilds a Hugo site.
No CI runners, no Docker-in-Docker — just a single container that clones, builds, and deploys.
How it works
git push → Forgejo webhook POST → hugo-webhook-deployer:9000
→ validates HMAC-SHA256 signature
→ filters for pushes to main
→ git pull + hugo --minify
→ output written to /output volume
Setup
1. Generate a deploy key
ssh-keygen -t ed25519 -f /tmp/deploy_key -N "" -C "hugo-deployer"
Add the public key to your Forgejo repo as a read-only deploy key (Settings → Deploy Keys):
cat /tmp/deploy_key.pub
Base64-encode the private key (you'll need this for DEPLOY_KEY_BASE64):
base64 -w0 /tmp/deploy_key
2. Generate a webhook secret
openssl rand -hex 32
Save this value — you'll set it in both the container config and the Forgejo webhook.
3. Configure environment variables
| Variable | Description |
|---|---|
WEBHOOK_SECRET |
The random string from step 2 (must match Forgejo webhook config) |
REPO_URL |
SSH clone URL for your repo, e.g. ssh://git@git.example.com:2222/org/repo.git |
DEPLOY_KEY_BASE64 |
The base64-encoded private key from step 1 |
See .env.example for a template.
4. Run the container
The /output volume should point to wherever your web server serves static files from (e.g. Apache's DocumentRoot).
The site-cache volume persists the cloned repo between restarts so subsequent builds are fast git pulls instead of full clones.
Docker CLI
docker run -d \
--name hugo-webhook \
-p 9000:9000 \
-v /var/www/your-site:/output \
-v site-cache:/site \
-e WEBHOOK_SECRET=your-secret \
-e REPO_URL=ssh://git@git.example.com:2222/org/repo.git \
-e DEPLOY_KEY_BASE64=$(base64 -w0 /tmp/deploy_key) \
--restart unless-stopped \
your-registry/hugo-webhook-deployer:latest
Docker Compose
See docker-compose.yml.example for a template.
Portainer
Create a new container or stack using the image and environment variables above.
5. Add the webhook in Forgejo
Go to your repo → Settings → Webhooks → Add Webhook (Gitea):
- Target URL:
http://<host>:9000/hooks/hugo-rebuild - Secret: same value as
WEBHOOK_SECRET - Trigger on: Push events
- Branch filter:
main
6. Verify
Push a commit to main and check the container logs:
docker logs -f hugo-webhook
SSH configuration
The port is specified in the REPO_URL via the ssh:// scheme (e.g. ssh://git@host:2222/org/repo.git). The built-in ssh_config also sets a default port — edit it if your Forgejo SSH port differs.
Building from source
make release # bump version, build, tag, push to registry
make build # bump + build only
make version # show current version
Components
- Hugo (extended edition, via
hugomods/hugo:exts) - adnanh/webhook — lightweight webhook receiver
- Alpine Linux 3.21