- Shipped
- August 20, 2026 at 3:48 AM UTC
- Author
- Kamo
- Commit
- 9e244db
Opening an assigned Linux instance always landed on Guacamole's generic "An error has occurred and this action cannot be completed" modal, and always worked after a refresh. The host-wide desktop-rate-limit was average 10 / burst 20, but a cold load of the SSO deep link fires ~41 requests inside one second. Traefik answered 23 and 429'd 18 of them -- including all three connectionGroups/ROOT/tree calls and the websocket-tunnel connect. Guacamole's userPageService.getHomePage() feeds those tree calls into a $q.all wired to requestService.DIE, so a single 429 there broadcasts guacFatalPageError and swaps the entire UI for APP.ERROR_PAGE_UNAVAILABLE -- the exact modal -- while the rejected tunnel meant nothing connected anyway. The refresh "fixed" it only because the second load serves the bundles from browser cache and so stays inside the bucket. One limit was being asked to do two jobs. Split them: the host keeps a page-load limit with real headroom (average 100 / burst 200, ~5x a cold load), and the credential-stuffing throttle keeps its original numbers on the one path that actually authenticates, POST /api/tokens. Guacamole's built-in per-IP ban remains the real brute-force control underneath. Both routes carry an explicit priority because kamo/kamo-nowww-route is a wildcard **************** catch-all sitting at priority 1 -- a desktop route that does not outrank it has the whole host swallowed and served 404s. Verified against the live gateway: the 41-request burst that previously returned 23x200 / 18x429 now returns 41x200 (120 concurrent also clean), while 30 requests to /api/tokens still throttle at 22 through / 8 rejected.