# 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; } } 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 two 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; } location / { return 404; } }