fix(cinny-nginx): own rate budget for content-hashed app files #40

Merged
jared merged 2 commits from fix/asset-rate-limit into main 2026-10-24 17:39:18 -04:00
Owner

Found while checking #449 in production: a fresh load of https://chat.lotusguild.org/register/matrix.org/ rendered blank. Four of its JavaScript chunks got 503 from LXC 106's nginx (limiting requests … zone "chat_limit").

Why: chat_limit allows 20 requests/s with a burst of 60 per client, which is too tight for how the app loads.

  • A cold page load fires 74 requests within one second (measured on the login page).
  • The service worker precaches all 126 build files at once, and every deploy renames them, so every user refetches them all after each deploy.
  • Both exceed 60, so some chunks are refused. That gives a blank page for a fresh visitor, or a failed precache install that retries.

Change: content-hashed static files (js|css|woff2|png|svg|ico|webp|wasm, in the app, Element Call on chat, and Element Call on call.chat) get their own assets_limit of 100 requests/s with a burst of 400, like decorations already do (matrix #22). Pages, the webhook and everything else keep chat_limit, so abuse protection where it matters is unchanged.

Who was hit recently (error logs, 30 days): mostly the scanner at 10.10.10.27 and cloud-provider bots, plus my own test runs. I found no clear sign of real users, but the measured page-load numbers show anyone could hit it.

Safety: the deploy runs nginx -t and restores the previous config on failure (deploy/lxc106-cinny.sh). I'll check afterwards with a fresh load of the matrix.org register page and the 503 count.

🤖 Generated with Claude Code

https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5

**Found while checking #449 in production:** a fresh load of `https://chat.lotusguild.org/register/matrix.org/` rendered blank. Four of its JavaScript chunks got **503** from LXC 106's nginx (`limiting requests … zone "chat_limit"`). **Why:** `chat_limit` allows 20 requests/s with a burst of 60 per client, which is too tight for how the app loads. - **A cold page load** fires **74 requests within one second** (measured on the login page). - **The service worker precaches all 126 build files at once**, and every deploy renames them, so every user refetches them all after each deploy. - Both exceed 60, so some chunks are refused. That gives a blank page for a fresh visitor, or a failed precache install that retries. **Change:** content-hashed static files (`js|css|woff2|png|svg|ico|webp|wasm`, in the app, Element Call on chat, and Element Call on call.chat) get their own `assets_limit` of 100 requests/s with a burst of 400, like decorations already do (matrix #22). Pages, the webhook and everything else keep `chat_limit`, so abuse protection where it matters is unchanged. **Who was hit recently** (error logs, 30 days): mostly the scanner at 10.10.10.27 and cloud-provider bots, plus my own test runs. I found no clear sign of real users, but the measured page-load numbers show anyone could hit it. **Safety:** the deploy runs `nginx -t` and restores the previous config on failure (`deploy/lxc106-cinny.sh`). I'll check afterwards with a fresh load of the matrix.org register page and the 503 count. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
jared added 1 commit 2026-10-24 17:05:12 -04:00
fix(cinny-nginx): give content-hashed app files their own rate budget
Lint / Shell (shellcheck) (pull_request) Successful in 15s
Lint / JS (eslint) (pull_request) Successful in 10s
Lint / No secrets in webhook configs (pull_request) Successful in 5s
Lint / Landing page is rendered (matrix (pull_request) Successful in 5s
Lint / Python (ruff) (pull_request) Successful in 6s
Lint / Python deps (pip-audit) (pull_request) Failing after 57s
Lint / Secret scan (gitleaks) (pull_request) Successful in 11s
Lint / Shell (shellcheck) (push) Successful in 11s
Lint / JS (eslint) (push) Successful in 9s
Lint / No secrets in webhook configs (push) Successful in 5s
Lint / Landing page is rendered (matrix (push) Successful in 5s
Lint / Python (ruff) (push) Successful in 8s
Lint / Python deps (pip-audit) (push) Failing after 51s
Lint / Secret scan (gitleaks) (push) Successful in 6s
ad7d735739
A cold page load fires ~75 requests within a second and the service worker
precaches all ~126 build files at once (every deploy renames them), both
past chat_limit's burst of 60. The excess got 503 "limiting requests":
a fresh visit to /register/matrix.org rendered blank (4 chunks refused),
and precache installs could fail after deploys. Like decorations (matrix
#22), hashed js/css/fonts/images/wasm now use assets_limit (100 r/s,
burst 400); pages and the webhook keep chat_limit. The deploy validates
with nginx -t and restores the old config on failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
Author
Owner

CI failed on pip-audit, unrelated to nginx: six new CVEs in filelock 4.1.0, which comes from pip-audit's own dependency (CacheControl). The bot doesn't use it, and the fixed 4.2.x needs Python 3.11 while the audit env is 3.10. Added them to the ignore list with that explanation, next to the existing pip one.

🤖 Generated with Claude Code

CI failed on **pip-audit**, unrelated to nginx: six new CVEs in `filelock` 4.1.0, which comes from pip-audit's own dependency (CacheControl). The bot doesn't use it, and the fixed 4.2.x needs Python 3.11 while the audit env is 3.10. Added them to the ignore list with that explanation, next to the existing pip one. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jared added 1 commit 2026-10-24 17:35:48 -04:00
ci(pip-audit): ignore filelock CVEs in pip-audit's own dependency
Lint / Shell (shellcheck) (push) Successful in 10s
Lint / JS (eslint) (push) Successful in 9s
Lint / No secrets in webhook configs (push) Successful in 7s
Lint / Landing page is rendered (matrix (push) Successful in 8s
Lint / Python (ruff) (push) Successful in 7s
Lint / Python deps (pip-audit) (push) Successful in 1m4s
Lint / Secret scan (gitleaks) (push) Successful in 6s
Lint / Shell (shellcheck) (pull_request) Successful in 13s
Lint / JS (eslint) (pull_request) Successful in 10s
Lint / No secrets in webhook configs (pull_request) Successful in 6s
Lint / Landing page is rendered (matrix (pull_request) Successful in 7s
Lint / Python (ruff) (pull_request) Successful in 6s
Lint / Python deps (pip-audit) (pull_request) Successful in 42s
Lint / Secret scan (gitleaks) (pull_request) Successful in 9s
d36c782e56
pip-audit --local scans the whole audit env, which includes pip-audit's
own CacheControl[filecache] -> filelock 4.1.0. Six new CVEs (fixed in
4.2.1) started failing every run; 4.2+ requires Python 3.11 and the audit
env is 3.10. The bot does not use filelock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
jared merged commit 2e6e8e72b8 into main 2026-10-24 17:39:18 -04:00
Sign in to join this conversation.