From 54152540340ce8bb5e1b6dbb38e4cf39e4db42ac Mon Sep 17 00:00:00 2001 From: Bas Grolleman Date: Sun, 13 Sep 2026 10:19:18 +0200 Subject: [PATCH] docs: comprehensive README with setup, usage, and pitfalls --- README.md | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 126 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0bd04eb..9669110 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,131 @@ Lightweight webhook container for NAS auto-deploy. Alpine-based with `docker-cli registry.gitlab.com/bgrolleman/nas-webhook:latest ``` -## Usage +Built automatically by GitLab CI on every push to `main`. Image is **public** — no registry login needed on the NAS to pull it. -See the [webhook documentation](https://github.com/adnanh/webhook) for hook configuration. +## How it works -Requires `/var/run/docker.sock` mounted to execute Docker commands from within the container. +1. A GitLab CI pipeline builds and pushes a new image (e.g. `hugo_basg.nl:latest`) +2. The CI pipeline sends a POST to `http://webhook.nas.basg.nl/hooks/` with a secret token in the `X-Webhook-Token` header +3. The webhook container receives the request, validates the token, and runs `deploy.sh ` +4. `deploy.sh` does `docker compose pull && docker compose up -d` in the project directory + +## Deployment on NAS + +Place the following files in a directory on the NAS (e.g. `/volume1/docker/webhook/`): + +``` +webhook/ +├── docker-compose.yml +├── hooks.json +└── scripts/ + └── deploy.sh +``` + +Then bring it up via the UGREEN web interface or `docker compose up -d`. + +The Docker socket (`/var/run/docker.sock`) must be mounted so the container can run Docker commands. The NAS docker directory (`/volume1/docker`) must also be mounted so `deploy.sh` can reach the project compose files. + +### docker-compose.yml + +```yaml +networks: + external: + external: true + +services: + webhook: + image: registry.gitlab.com/bgrolleman/nas-webhook:latest + restart: always + command: ["-hooks", "/config/hooks.json", "-verbose", "-hotreload"] + volumes: + - ./hooks.json:/config/hooks.json:ro + - ./scripts:/scripts:ro + - /var/run/docker.sock:/var/run/docker.sock + - /volume1/docker:/volume1/docker + expose: + - 9000 + environment: + - VIRTUAL_HOST=webhook.nas.basg.nl + - VIRTUAL_PORT=9000 + networks: + - external +``` + +Note: No `LETSENCRYPT_HOST` — running HTTP only. The ACME challenge (Let's Encrypt) doesn't work for this container because it only exposes port 9000, not 80. Since it's only called by GitLab CI (not a browser), HTTP is fine. + +## Adding a new project + +### 1. Add a hook to `hooks.json` + +```json +{ + "id": "my-project", + "execute-command": "/scripts/deploy.sh", + "command-working-directory": "/scripts", + "pass-arguments-to-command": [ + { + "source": "string", + "name": "/volume1/docker/my-project" + } + ], + "trigger-rule": { + "match": { + "type": "value", + "value": "YOUR_SECRET_TOKEN_HERE", + "parameter": { + "source": "header", + "name": "X-Webhook-Token" + } + } + } +} +``` + +Generate a token with: `openssl rand -hex 32` + +The webhook container uses `-hotreload` so it picks up `hooks.json` changes without a restart. + +### 2. Add deploy stage to the project's `.gitlab-ci.yml` + +Store the token as a masked CI variable (e.g. `DEPLOY_WEBHOOK_TOKEN`) in the GitLab project settings. + +```yaml +deploy: + stage: deploy + image: alpine:latest + before_script: + - apk add --no-cache curl + script: + - | + curl -f -X POST \ + -H "X-Webhook-Token: $DEPLOY_WEBHOOK_TOKEN" \ + http://webhook.nas.basg.nl/hooks/my-project + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + needs: [build] +``` + +### 3. Make sure the project image is public + +The NAS pulls images without authentication. Either make the GitLab registry public (project → Settings → General → Visibility → Public) or set up a deploy token and run `sudo docker login registry.gitlab.com` on the NAS. + +## Testing a hook manually + +```bash +curl -X POST \ + -H "X-Webhook-Token: YOUR_TOKEN" \ + http://webhook.nas.basg.nl/hooks/your-hook-id +``` + +## Current hooks + +| Hook ID | Project | Compose dir | +|---------|---------|-------------| +| `hugo-basg` | bgrolleman/hugo_basg.nl | `/volume1/docker/basg-hugo` | + +## Known issues / pitfalls + +- **No HTTPS**: Let's Encrypt won't issue a cert because the container doesn't serve HTTP on port 80. Since only GitLab CI calls this endpoint, HTTP is acceptable. If HTTPS is needed in the future, put a separate nginx container in front that handles port 80/443 and proxies to port 9000. +- **Docker socket permissions**: The webhook runs as root inside the container (required to use the socket). This is standard for Docker-in-Docker patterns on a home NAS. +- **Image must be public or NAS must be logged in**: The deploy script runs `docker compose pull` which needs registry access. Easiest solution is a public GitLab project.