C1: shower-specific rate-limit zone for venue-wifi NAT
Default `general` zone (10r/s burst=20) is tuned for internet drive-by traffic. At the party, 30 guests scanning the splash QR from one venue-wifi NAT'd public IP would each fetch HTML + ~5 static assets within a few seconds — easily clearing burst=20, and the second-wave guests would see 503 with no auto-retry. New shower_general zone (50r/s burst=200) absorbs that simultaneous- load spike. Exploit scanners still trip it: the 45.88.138.44 burst we already saw in Loki fired ~30 req in 2s, well above the new sustained 50r/s when extrapolated, and burst=200 is still a hard cap on instantaneous spikes. Self-healing: `limit_req` is a token bucket — no persistent ban, nothing to manually flush. A guest who trips it auto-recovers within ~1s; tuning here is about not tripping it on legit traffic in the first place. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c430528583
commit
fb6067b620
1 changed files with 16 additions and 2 deletions
|
|
@ -34,6 +34,15 @@ http {
|
||||||
# bucket. $http_fly_client_ip has the actual client IP.
|
# bucket. $http_fly_client_ip has the actual client IP.
|
||||||
limit_req_zone $http_fly_client_ip zone=forge_auth:10m rate=3r/s;
|
limit_req_zone $http_fly_client_ip zone=forge_auth:10m rate=3r/s;
|
||||||
|
|
||||||
|
# Shower-specific zone: loose enough that ~30 guests sharing a single
|
||||||
|
# venue-wifi NAT'd public IP can all scan the QR and load the splash
|
||||||
|
# (HTML + a handful of static asset hits each) without anyone tripping
|
||||||
|
# the limit. 50r/s + burst=200 covers the simultaneous-load spike;
|
||||||
|
# exploit scanners still trip it (e.g. the .env-sweeping bot we saw
|
||||||
|
# fired ~30 req in 2s — that pattern stays caught). See the
|
||||||
|
# shower.eblu.me server block for the matching `limit_req`.
|
||||||
|
limit_req_zone $http_fly_client_ip zone=shower_general:10m rate=50r/s;
|
||||||
|
|
||||||
# fail2ban deny list — banned IPs are written here by fail2ban and
|
# fail2ban deny list — banned IPs are written here by fail2ban and
|
||||||
# checked via the $forge_banned variable. The file is touched at
|
# checked via the $forge_banned variable. The file is touched at
|
||||||
# container start to ensure it exists.
|
# container start to ensure it exists.
|
||||||
|
|
@ -318,8 +327,13 @@ http {
|
||||||
listen 8080;
|
listen 8080;
|
||||||
server_name shower.eblu.me;
|
server_name shower.eblu.me;
|
||||||
|
|
||||||
# General per-IP rate limit (cushion for the splash page + form posts)
|
# Per-IP rate limit. shower_general (50r/s, burst=200) instead of
|
||||||
limit_req zone=general burst=20 nodelay;
|
# the global `general` zone because at the party, guests on the
|
||||||
|
# venue's wifi all NAT through a single Fly-Client-IP — 30 guests
|
||||||
|
# scanning the QR at once would each fetch HTML + a few static
|
||||||
|
# assets, easily clearing 20 burst on `general`. Exploit scanners
|
||||||
|
# still trip it (sustained ≫ 50r/s patterns).
|
||||||
|
limit_req zone=shower_general burst=200 nodelay;
|
||||||
|
|
||||||
# Image uploads from /host/'s prize cropper are ~150-300 KiB JPEGs.
|
# Image uploads from /host/'s prize cropper are ~150-300 KiB JPEGs.
|
||||||
# The host page itself isn't reachable here, but /media/ reads can
|
# The host page itself isn't reachable here, but /media/ reads can
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue