From a52d6a89bce2c5df7c142c0e839ae8fb463a7b86 Mon Sep 17 00:00:00 2001 From: Lotus CI Date: Mon, 19 Oct 2026 12:41:46 -0400 Subject: [PATCH] fix(cinny-web): per-client rate limits; own budget for decorations Every request reaches LXC 106 from Nginx Proxy Manager (10.10.10.27), and nginx had no realip config, so chat_limit (20 r/s, burst 60, keyed by $binary_remote_addr) was ONE bucket for the whole community: a scanner burst 503ed real users. Trust X-Real-IP from the proxy only, in both server blocks. Decorations (#22) now come from this host, and the profile picker can fetch all 629 thumbnails: ~500 of them 503ed in testing. /decorations/ gets its own zone (100 r/s, burst 700) instead of chat_limit. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5 --- cinny/nginx.conf | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/cinny/nginx.conf b/cinny/nginx.conf index 8d1a813..68c3376 100644 --- a/cinny/nginx.conf +++ b/cinny/nginx.conf @@ -7,6 +7,17 @@ map $uri $lotus_shell_cache_control { default ""; } +# All traffic arrives through Nginx Proxy Manager (10.10.10.27), so without +# realip every visitor shared ONE chat_limit bucket (20 r/s, keyed by +# $binary_remote_addr = the proxy): a scanner burst got real users 503s. +# Each server block below trusts X-Real-IP from the proxy only (NPM sets it +# to the client address, overwriting anything the client sent). +# +# [matrix #22] Decorations get their own, larger budget: opening the profile +# decoration picker can fetch hundreds of thumbnails, which would otherwise use +# up chat_limit and 503 the app's own files. +limit_req_zone $binary_remote_addr zone=decorations_limit:10m rate=100r/s; + server { listen 80; listen [::]:80; @@ -23,6 +34,8 @@ server { server_tokens off; client_max_body_size 50m; + set_real_ip_from 10.10.10.27; + real_ip_header X-Real-IP; limit_req zone=chat_limit burst=60 nodelay; limit_conn chat_conn 25; index index.html; @@ -113,6 +126,9 @@ server { # can be replaced in place under the same name, so a week, not immutable. location ^~ /decorations/ { alias /var/www/decorations/; + # Replaces the server-level chat_limit here (nginx doesn't inherit + # limit_req into a location that sets its own). + limit_req zone=decorations_limit burst=700 nodelay; include snippets/cinny-security-headers.conf; add_header Cache-Control "public, max-age=604800" always; location ~ /MANIFEST\.sha256$ { return 404; } @@ -151,6 +167,8 @@ server { root /var/www/html; server_tokens off; + set_real_ip_from 10.10.10.27; + real_ip_header X-Real-IP; limit_req zone=chat_limit burst=60 nodelay; limit_conn chat_conn 25;