feat: enhance deployment documentation and nginx configuration for Gitea webhook handling

This commit is contained in:
Sascha 2026-07-29 18:20:39 +02:00
parent 960943bd60
commit aaa9a9f567
2 changed files with 57 additions and 13 deletions

View File

@ -222,18 +222,25 @@ Without this, updating means SSHing in and running the commands under
"Updating later" by hand every time. This section makes a `git push` to "Updating later" by hand every time. This section makes a `git push` to
your own Gitea/Forgejo trigger a pull + restart automatically. your own Gitea/Forgejo trigger a pull + restart automatically.
Since Git already runs on this same VPS, the webhook listener never needs to **Check this first:** run `docker ps` to see whether Gitea/Forgejo runs in a
be reachable from the internet - it binds to `127.0.0.1` only, and Gitea Docker container. This decides which of the two setups below applies.
calls it over loopback. Nothing new is exposed publicly.
**Check this first:** if Gitea/Forgejo runs inside Docker, `127.0.0.1` inside **Gitea runs natively on this machine (not in Docker):** the webhook listener
its container is the container's own loopback, not the host's - the webhook never needs to be reachable from the internet - it binds to `127.0.0.1`
target below would not connect. Run `docker ps` to check. If Gitea is only, and Gitea calls it over loopback. Use `http://127.0.0.1:3002/deploy-webhook`
containerized, either add the webhook service to the same Docker network and as the Target URL in step 11.4 and skip the nginx part of step 11.3.
call it by container name, or expose the webhook through the nginx vhost
(same pattern as `/api/audit-request` in step 7) with an `allow`/`deny` block **Gitea runs in Docker:** inside that container, `127.0.0.1` is the
restricting it to the container network's subnet, instead of the loopback container's own loopback, not this host - a target of `127.0.0.1:3002` would
target used below. never connect, regardless of Docker's networking mode. Rather than depending
on that container's specific network setup (bridge vs. host, custom networks,
`host.docker.internal` availability - all of which vary by how it was set
up), route the webhook through the same nginx vhost as the audit endpoint
instead: the request just goes out over HTTPS to `api.sascha-bach.de` and
back in, exactly like any other webhook call, independent of how Gitea's
container is networked. `backend/deploy/nginx-api.sascha-bach.de.conf`
already has the `/deploy-webhook` location for this - see step 11.3. Use
`https://api.sascha-bach.de/deploy-webhook` as the Target URL in step 11.4.
### 11.1 Generate a secret and configure it ### 11.1 Generate a secret and configure it
@ -274,6 +281,17 @@ sudo systemctl enable --now audit-webhook
systemctl status audit-webhook --no-pager systemctl status audit-webhook --no-pager
``` ```
**Only if Gitea runs in Docker**, additionally expose it through nginx (the
config was already updated when you copied it in step 7 - if that was before
this section existed, re-copy it):
```bash
sudo cp /opt/audit-endpoint/backend/deploy/nginx-api.sascha-bach.de.conf \
/etc/nginx/sites-available/api.sascha-bach.de
sudo nginx -t
sudo systemctl reload nginx
```
### 11.4 Register the webhook in Gitea/Forgejo ### 11.4 Register the webhook in Gitea/Forgejo
In the repository on `git.sascha-bach.de`: **Settings → Webhooks → Add In the repository on `git.sascha-bach.de`: **Settings → Webhooks → Add
@ -282,7 +300,7 @@ Gitea fork and uses the same webhook format).
| Field | Value | | Field | Value |
| --- | --- | | --- | --- |
| Target URL | `http://127.0.0.1:3002/deploy-webhook` | | Target URL | `http://127.0.0.1:3002/deploy-webhook` (native Gitea) **or** `https://api.sascha-bach.de/deploy-webhook` (Gitea in Docker) |
| HTTP Method | `POST` | | HTTP Method | `POST` |
| POST Content Type | `application/json` | | POST Content Type | `application/json` |
| Secret | the value generated in 11.1 | | Secret | the value generated in 11.1 |

View File

@ -22,6 +22,13 @@ server {
} }
} }
# Rate-limits /deploy-webhook specifically. It is now reachable over the
# public hostname (see the location block below), so unlike
# /api/audit-request it has no per-request Node-side limiter of its own -
# the HMAC signature check is the real gate, this is just a cheap first
# filter against noise.
limit_req_zone $binary_remote_addr zone=deploy_webhook:1m rate=10r/m;
server { server {
listen 443 ssl; listen 443 ssl;
listen [::]:443 ssl; listen [::]:443 ssl;
@ -34,7 +41,7 @@ server {
# so they never reach it. # so they never reach it.
client_max_body_size 16k; client_max_body_size 16k;
# Only these two paths exist. Everything else is refused rather than # Only these paths exist. Everything else is refused rather than
# forwarded, which keeps the attack surface to what the form needs. # forwarded, which keeps the attack surface to what the form needs.
location = /api/audit-request { location = /api/audit-request {
proxy_pass http://127.0.0.1:3001; proxy_pass http://127.0.0.1:3001;
@ -57,6 +64,25 @@ server {
access_log off; access_log off;
} }
# Only needed if Gitea/Forgejo runs in a Docker container: 127.0.0.1
# inside that container is the container's own loopback, not this host,
# so the webhook target can't be http://127.0.0.1:3002 in that case.
# Routing it here instead works regardless of the container network
# setup - the request simply goes out over HTTPS to this hostname and
# back in, the same way any other webhook call would.
#
# If Gitea runs natively on this same machine (not in Docker), this
# block is not needed - point the Gitea webhook straight at
# http://127.0.0.1:3002/deploy-webhook instead and skip this location.
location = /deploy-webhook {
limit_req zone=deploy_webhook burst=5 nodelay;
proxy_pass http://127.0.0.1:3002;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 30s;
}
location / { location / {
return 404; return 404;
} }