# Rate Limit Backfires: When 60 Requests Break a SaaS

> Published 2026-11-04T12:14:44.456Z on https://youblog.app/p/rate-limit-backfires-when-60-requests-break-a-saas/
> Source video: https://www.youtube.com/watch?v=kzhwRoNnzfU

A rate limit backfires when it counts normal browsing as an attack. In one Rails SaaS, a global cap of 60 requests per minute was set after a DDoS scare, and it ended up locking out ordinary visitors, because a single home page load could burn more than 50 of those requests.

## Why a rate limit backfires after a DDoS scare

A rate limit backfires when it is tuned during post-incident adrenaline and never tested against real navigation. The SaaS in this case had survived a reported 260 million requests in one day, and the owner set a global cap of 60 requests per minute per IP as a safeguard, without a load test or a walkthrough of a normal user session.

The incident ran on a two-core VPS. According to the channel's account, load reached about 88, SSH access failed, and after six hours of debugging the owner deleted the server and rebuilt it with boot-time firewall rules, a pinned proxy version, Cloudflare's Under Attack mode, and the global rate limit.

That rebuild treated traffic volume as the enemy. It never asked how much traffic one honest visitor creates, which is the number a global limit actually has to clear.

## What the rate limit backfires diagnosis looked like

The site started returning 429 Too Many Requests during ordinary use, including screen shares on live streams. The owner first read the errors as a fresh attack, then reproduced them alone with no scripts running and no flood in progress.

The diagnostic path matters more than the tool list. Infrastructure metrics showed a machine with a CPU average of 3.8 percent and a peak of 4.71 percent over the inspected window, memory and disk within normal range, and no anomaly across 744 samples covering 15 days. A traffic spike on August 5, 2026 reached about 99.5 MB inbound, which was small in absolute terms.

With the server ruled out, the error had to come from application logic. Opening [Claude Code](https://github.com/anthropics/claude-code), Anthropic terminal coding agent, against the host's official connector let the owner query VPS metrics, DNS, firewall state and deployments through an API instead of SSH. The measured finding was simple: the machine was idle while the app refused requests.

## How 53 requests from one page view broke a 60 request cap

A Rails page view is not a single request. The rate limit counted everything except the assets folder, and product logos served through Active Storage were counted one by one, so a home page with 50 products produced roughly 50 image requests plus the page itself.

Two more multipliers pushed a normal session past 60 per minute. Turbo prefetches a link when the pointer hovers over it, so each hover counted as another request against the same limit. And Brazilian ISPs commonly use carrier-grade NAT, which places many subscribers behind one public IP, so two people on the same network could exhaust a shared budget together.

The arithmetic is unforgiving. One page load consumed about 53 of 60 allowed requests. Any second action inside the same minute, such as opening a product, refreshing, or letting prefetch fire on a few links, crossed the line.

## What the fix changed in the throttle configuration

The correction scoped the throttle instead of removing it. An exemption list was extracted as a constant for path prefixes that should never count toward the global limit: assets, Active Storage, icons, uploads, favicon and robots.txt. The blanket rule was replaced with a prefix-aware exemption, and the 429 response now returns an HTML body rather than bare JSON.

A regression test was added to simulate the original pattern, and the project documentation was updated alongside the code. The change was committed, pushed and reviewed as a pull request before deployment.

The general lesson transfers beyond Rails: a rate limit keyed by IP needs an exemption list for static and stored media, a budget sized against real page weight, and a keying strategy that accounts for shared IP addresses.

## How to size and test a rate limit before it ships

Size the limit from measured per-session request counts, not from the size of the attack you fear. Then verify it with real browsing, including hover prefetch, image-heavy pages, and repeated navigation inside one minute.

- Count requests for one full page load, including every image served by storage.
- Multiply by the actions a typical user takes in a minute, then add headroom.
- Exempt static assets, stored media, favicon and robots.txt from the global budget.
- Check whether carrier-grade NAT puts many users behind one IP, and choose a key that survives it.
- Add a regression test that reproduces the original failure.
- Exercise the throttle in development with refreshes and hovering, not only with a load generator.

| Setting | Before | After |
| --- | --- | --- |
| Global limit | 60 requests/min per IP | Kept, but scoped |
| Exempt paths | assets only | assets, Active Storage, icons, uploads, favicon, robots.txt |
| 429 body | JSON | HTML page |
| Regression test | none | reproduces the original pattern |

The table above reflects what the video shows in the merged change. Treat it as one operator's configuration for one Rails application, not as a template with tested performance numbers.

## Why 429 errors are not proof of a DDoS attack

A 429 response means a request was refused by a limiter, and that can happen with one user on the site. Announcement traffic looks like abuse from inside a panic: a video goes live, viewers click through, and request volume rises in a way the operator did not plan for.

The 2025 and 2026 DDoS record reports describe a different scale entirely. Cloudflare reported mitigating a 22.2 Tbps attack lasting about 40 seconds, according to [CISO Advisor](https://www.cisoadvisor.com.br/ataque-ddos-atinge-222-tbps/), and Microsoft reported blocking a 15.72 Tbps flood from roughly 500,000 IPs, per [Canaltech](https://canaltech.com.br/seguranca/microsoft-bloqueia-ataque-ddos-monstruoso-de-15-tbps-feito-por-500-mil-aparelhos/). Those figures describe volumetric network attacks, which is not what a per-IP application throttle measures.

Before blaming an attack, check server metrics. An idle CPU with steady memory and disk during 429 errors points at the application layer and at your own configuration. For anyone learning this kind of debugging, materials such as the Bootcamp do Dev Doido and communities around Gustavo Dev Doido cover deployment and infrastructure habits that make the check routine.

## FAQ

- **What does it mean when a rate limit backfires?** A rate limit backfires when the cap is lower than the request volume created by legitimate users, so normal browsing triggers 429 errors. In this case a 60 requests per minute limit was smaller than the roughly 53 requests a single page load consumed.

- **Why did a global rate limit break a Rails app?** Rails counted storage-served images, prefetch requests and every non-asset path against one per-IP budget. Product logos through Active Storage alone added about 50 requests per page, leaving almost no room for a second click.

- **What is Turbo prefetch and how does it affect limits?** Turbo prefetches a page when the pointer hovers over a link, so the browser sends extra requests before the user clicks. Each hover consumes part of the same rate limit budget, which makes a low cap easy to exhaust during normal navigation.

- **How does CGNAT make per-IP limits stricter?** Carrier-grade NAT places many subscribers behind one public IP address. A per-IP limit is then shared by everyone on that network, so two users visiting at once can exhaust a budget sized for one person.

- **Is a 429 error proof of a DDoS attack?** No. A 429 means a limiter refused the request, which can happen with a single user. Verifying an attack requires traffic and resource evidence at network level, not just an application error page.

- **What should be exempt from a global rate limit?** Static assets, Active Storage files, icons, uploads, favicon and robots.txt are the usual candidates. These paths are requested repeatedly by the browser and rarely represent abuse on their own.

- **Should you remove the rate limit entirely after this kind of failure?** Removing it returns the app to its pre-incident state. The safer move is to keep the limit, scope it by path and by an appropriate key, then test it with realistic browsing patterns.

- **How do you test a rate limit before deploying?** Reproduce a real session in development: load an image-heavy page, hover over links, refresh repeatedly within one minute and open products. Add a regression test that fails if the balance flips again.

- **Why use an infrastructure connector instead of SSH for debugging?** SSH access from an agent gives broad control with little audit surface. A connector exposed through an official API lets an agent read metrics, DNS and firewall state while keeping write actions scoped and reviewable.

- **What happened to the 260 million requests incident?** The earlier attack overwhelmed a two-core VPS, forcing a rebuild. The later outage was self-inflicted by the rebuilt configuration, which is why the owner frames overcorrection as the new downtime.

## Turning a painful incident into something readable

The most useful part of this story is the sequence: an attack, a rushed defense, a false alarm, and a quiet configuration bug that only real users exposed. Anyone who has debugged production at night recognizes that shape, and it rarely gets written down while the details are fresh.

If your own videos hold that kind of hard-won detail, [Skala Blog](https://skalablog.com) turns a YouTube link into a transcribed draft you can edit and publish. Paste the URL, let it transcribe, and shape the result into an article that preserves the reasoning your audience came for.

For teams standardizing on a modern stack while they build these habits, [Crazystack Typescript](https://crazystack.com.br) is a full-stack TypeScript training option worth reviewing.

[Source video](https://www.youtube.com/watch?v=kzhwRoNnzfU)
