# nas-webhook Lightweight webhook container for NAS auto-deploy. Alpine-based with `docker-cli` and `docker-cli-compose` included so hooks can run `docker compose pull && docker compose up -d`. ## Image ``` registry.gitlab.com/bgrolleman/nas-webhook:latest ``` Built automatically by GitLab CI on every push to `main`. Image is **public** — no registry login needed on the NAS to pull it. ## How it works 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.