feat(proxy): add per-IP rate and connection limits

The edge had no limit_req/limit_conn at all, so a single client could
flood the Next.js backend and the Nitro client with unbounded parallel
requests. Traefik's logs already showed this: bursts of gamedata icon
requests answered with 429.

Add limit_req (30r/s, burst 60, nodelay) and limit_conn (30) zones keyed
on the real client IP, applied at server scope so both cached assets and
proxied API routes share one budget. The burst is deliberately generous
because the Nitro client fetches gamedata and icons in bursts when
loading a room.
This commit is contained in:
openhands committed 2026-10-01 17:25:49 +02:00
1 parent e3c010f383
commit 4a1211a931
2 files changed
+13

No files matched your search

+7
View File
@@ -192,6 +192,13 @@ server {
keepalive_timeout 30s;
send_timeout 10s;
# Abuse limits. Applied per server, not per location, so cached assets and
# proxied API routes are all covered by the same budget. nodelay keeps the
# 60-request burst responsive: allowed requests pass immediately, only the
# excess is rejected with 503 instead of being queued.
limit_req zone=cms_req_per_ip burst=60 nodelay;
limit_conn cms_conn_per_ip 30;
# Traefik health-check route herstellen
location = /health {
access_log off;
+6
View File
@@ -44,6 +44,12 @@ http {
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;
# Rate limiting per client IP. The Nitro client fetches gamedata and icons in
# bursts when booting a room, so the burst is deliberately generous: it caps
# sustained floods without punishing a normal room load.
limit_req_zone $binary_remote_addr zone=cms_req_per_ip:10m rate=30r/s;
limit_conn_zone $binary_remote_addr zone=cms_conn_per_ip:10m;
# Blue/green cutover: ci-deploy.sh writes the active upstream here, and
# `proxy_pass http://cms_app` below follows it via graceful nginx -s reload.
upstream cms_app {