90 lines
3.3 KiB
Plaintext
90 lines
3.3 KiB
Plaintext
# Reverse proxy for the audit request endpoint.
|
|
#
|
|
# Deliberately a separate server block on its own hostname, so it does not
|
|
# touch the existing git / nextcloud vhosts on this machine. Reload nginx
|
|
# rather than restarting it, and the other services never drop a connection.
|
|
#
|
|
# Install to /etc/nginx/sites-available/api.sascha-bach.de and symlink into
|
|
# sites-enabled. certbot --nginx rewrites the TLS parts of this file.
|
|
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name api.sascha-bach.de;
|
|
|
|
# Needed once so certbot can answer the HTTP-01 challenge.
|
|
location /.well-known/acme-challenge/ {
|
|
root /var/www/html;
|
|
}
|
|
|
|
location / {
|
|
return 301 https://$host$request_uri;
|
|
}
|
|
}
|
|
|
|
# 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 {
|
|
listen 443 ssl;
|
|
listen [::]:443 ssl;
|
|
http2 on;
|
|
server_name api.sascha-bach.de;
|
|
|
|
# certbot inserts ssl_certificate / ssl_certificate_key here.
|
|
|
|
# The Node process caps bodies at 10 kB. Reject oversized ones at the edge
|
|
# so they never reach it.
|
|
client_max_body_size 16k;
|
|
|
|
# Only these paths exist. Everything else is refused rather than
|
|
# forwarded, which keeps the attack surface to what the form needs.
|
|
location = /api/audit-request {
|
|
proxy_pass http://127.0.0.1:3001;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
# Required: server.js runs with `trust proxy 1` and derives the
|
|
# rate-limit key from this header. Without it every visitor shares
|
|
# one bucket and three submissions lock out everyone for 15 minutes.
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_read_timeout 30s;
|
|
}
|
|
|
|
location = /health {
|
|
proxy_pass http://127.0.0.1:3001;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
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 / {
|
|
return 404;
|
|
}
|
|
}
|