Lower the default request and byte limits; the hourly request count is the main signal #193

Open
opened 2026-11-06 18:21:52 +01:00 by clawbot · 7 comments
Collaborator

sneak, in chat on 6 November:

The rate limits on request counts per unit of time in small web WAF need to be dropped a lot. I think that the per hour request count is probably going to be the biggest signal. It should absolutely not be more than 30 times the per minute request limit. We are going to be dealing with identifying specific clients that send large numbers of requests at something less than 10 requests per second, but send many, many requests over the course of hours or days. The per minute request limit is going to be a big signal as well.

please propose for me appropriate per minute, per hour, and per day request counts and byte counts based on legitimate users being allowed and scraper bots not.

The defaults today are 500 requests a minute, 20,000 an hour and 300,000 a day, and 4G, 20G and 200G of bytes (SWWAF_RATE_LIMIT_PER_*, SWWAF_BYTES_LIMIT_PER_*).

Definition of done:

  • The six defaults are the figures sneak approves on this issue, in the code and in the README's settings table.
  • The default hourly request limit is at most 30 times the default per-minute limit.
  • The tests that pin the defaults are updated, and make check passes.

Model: opus-5-5

sneak, in chat on 6 November: > The rate limits on request counts per unit of time in small web WAF need to be dropped a lot. I think that the per hour request count is probably going to be the biggest signal. It should absolutely not be more than 30 times the per minute request limit. We are going to be dealing with identifying specific clients that send large numbers of requests at something less than 10 requests per second, but send many, many requests over the course of hours or days. The per minute request limit is going to be a big signal as well. > > please propose for me appropriate per minute, per hour, and per day request counts and byte counts based on legitimate users being allowed and scraper bots not. The defaults today are 500 requests a minute, 20,000 an hour and 300,000 a day, and 4G, 20G and 200G of bytes (`SWWAF_RATE_LIMIT_PER_*`, `SWWAF_BYTES_LIMIT_PER_*`). **Definition of done:** - The six defaults are the figures sneak approves on this issue, in the code and in the README's settings table. - The default hourly request limit is at most 30 times the default per-minute limit. - The tests that pin the defaults are updated, and `make check` passes. Model: opus-5-5
Author
Collaborator

Proposal, for each client (one IPv4 address, or one IPv6 /64):

  • Requests: 120 a minute, 1,500 an hour, 6,000 a day.
  • Bytes: 500M a minute, 1G an hour, 4G a day.

Why these figures:

  • 120 a minute allows a person opening several pages at once with a cold cache. A Gitea page with its scripts, styles and avatars is 20 to 60 requests the first time, then a handful once cached. It stops anything faster than 2 requests a second within a minute.
  • 1,500 an hour (12.5 times the minute figure, under your 30) is the main signal. Someone reading code in Gitea for a whole hour, one page every 20 seconds, makes about 900 requests. A scraper at one request every 2 seconds hits the limit within 50 minutes.
  • 6,000 a day is four of those heavy hours, more than a person spends on one small site. A scraper at one request every 10 seconds is caught within 17 hours. What still gets through is about 4 requests a minute around the clock, at most 6,000 pages a day per address.
  • Bytes: a person's large downloads come in bursts, such as a git clone or a release file, so the minute figure allows one clone of up to 500 MB. Scrapers that pull every commit's archive download steadily, and the hour and day figures stop them. On a small static site, pages are about 1 MB, so the request limits bind first.

Three things to set alongside the defaults:

  • Gitea Actions runners ask the server for work every 2 seconds, about 1,800 requests an hour, and would be banned. Put each runner's address in SWWAF_RATE_LIMIT_EXEMPT_NETS, with your own addresses.
  • Everyone behind one shared address, such as an office or a university, shares one budget. Exempt such a network the same way if it matters.
  • If Gitea's asset paths are left out of the counts (SWWAF_RATE_LIMIT_EXEMPT_PATHS, such as /assets/ and /avatars/), the minute figure can drop to 60.

Every limit bans on the first request over it (1 hour, three times longer on a repeat), so a too-low figure locks out real people. That is why the minute figure sits higher than scrapers alone would justify.

Question: approve these six figures as the new defaults? Recommended: yes.

Model: opus-5-5

**Proposal**, for each client (one IPv4 address, or one IPv6 /64): - **Requests:** 120 a minute, 1,500 an hour, 6,000 a day. - **Bytes:** 500M a minute, 1G an hour, 4G a day. **Why these figures:** - **120 a minute** allows a person opening several pages at once with a cold cache. A Gitea page with its scripts, styles and avatars is 20 to 60 requests the first time, then a handful once cached. It stops anything faster than 2 requests a second within a minute. - **1,500 an hour** (12.5 times the minute figure, under your 30) is the main signal. Someone reading code in Gitea for a whole hour, one page every 20 seconds, makes about 900 requests. A scraper at one request every 2 seconds hits the limit within 50 minutes. - **6,000 a day** is four of those heavy hours, more than a person spends on one small site. A scraper at one request every 10 seconds is caught within 17 hours. What still gets through is about 4 requests a minute around the clock, at most 6,000 pages a day per address. - **Bytes:** a person's large downloads come in bursts, such as a git clone or a release file, so the minute figure allows one clone of up to 500 MB. Scrapers that pull every commit's archive download steadily, and the hour and day figures stop them. On a small static site, pages are about 1 MB, so the request limits bind first. **Three things to set alongside the defaults:** - Gitea Actions runners ask the server for work every 2 seconds, about 1,800 requests an hour, and would be banned. Put each runner's address in `SWWAF_RATE_LIMIT_EXEMPT_NETS`, with your own addresses. - Everyone behind one shared address, such as an office or a university, shares one budget. Exempt such a network the same way if it matters. - If Gitea's asset paths are left out of the counts (`SWWAF_RATE_LIMIT_EXEMPT_PATHS`, such as `/assets/` and `/avatars/`), the minute figure can drop to 60. Every limit bans on the first request over it (1 hour, three times longer on a repeat), so a too-low figure locks out real people. That is why the minute figure sits higher than scrapers alone would justify. **Question:** approve these six figures as the new defaults? Recommended: yes. Model: opus-5-5
sneak was assigned by clawbot 2026-11-06 18:21:53 +01:00
Author
Collaborator

sneak, in chat on 6 November:

i don’t think per minute byte limits should be that low, that’s only 60Mbps. i am fine with unlimited bytes per minute. an hour should be 1500MB which is 200Mbps. 20-40GB a day is reasonable, I think?

Revised byte figures:

  • Per minute: off.
  • Per hour: 1500M. That averages 3.3 Mbps over the hour; 200 Mbps would be 1500 MB a minute. With the minute limit off, a client can still pull the whole 1500 MB at full line speed. It is banned only on the byte past it, so bursts are untouched.
  • Per day: 20G. At 1500 MB an hour, the most any client can take in a day is 36 GB, so a 40 GB day limit would never apply. 20 GB stops a client that pulls at the hourly limit around the clock after about 13 hours.

The request figures stand as proposed above: 120 a minute, 1,500 an hour, 6,000 a day.

Question: approve requests 120 / 1,500 / 6,000 and bytes off / 1500M / 20G as the new defaults? Recommended: yes.

Model: opus-5-5

sneak, in chat on 6 November: > i don’t think per minute byte limits should be that low, that’s only 60Mbps. i am fine with unlimited bytes per minute. an hour should be 1500MB which is 200Mbps. 20-40GB a day is reasonable, I think? **Revised byte figures:** - **Per minute:** `off`. - **Per hour:** `1500M`. That averages 3.3 Mbps over the hour; 200 Mbps would be 1500 MB a minute. With the minute limit off, a client can still pull the whole 1500 MB at full line speed. It is banned only on the byte past it, so bursts are untouched. - **Per day:** `20G`. At 1500 MB an hour, the most any client can take in a day is 36 GB, so a 40 GB day limit would never apply. 20 GB stops a client that pulls at the hourly limit around the clock after about 13 hours. The request figures stand as proposed above: 120 a minute, 1,500 an hour, 6,000 a day. **Question:** approve requests 120 / 1,500 / 6,000 and bytes `off` / `1500M` / `20G` as the new defaults? Recommended: yes. Model: opus-5-5
Author
Collaborator

The byte figures moved to the proposal on #194, after sneak pointed out that 1500 MB an hour blocks a single 3 GB download. There, the plain byte limits are loose (none a minute, 10 GB an hour, 30 GB a day), and a new rule takes a client with many recent requests down to 2 GB a day. The request figures proposed here (120 a minute, 1,500 an hour, 6,000 a day) still wait for his yes.

Model: opus-5-5

The byte figures moved to the proposal on https://git.eeqj.de/sneak/smallwebwaf/issues/194, after sneak pointed out that 1500 MB an hour blocks a single 3 GB download. There, the plain byte limits are loose (none a minute, 10 GB an hour, 30 GB a day), and a new rule takes a client with many recent requests down to 2 GB a day. The request figures proposed here (120 a minute, 1,500 an hour, 6,000 a day) still wait for his yes. Model: opus-5-5
Author
Collaborator

Approved by sneak in chat on 6 November ("yes and yes"). The new default request limits are 120 a minute, 1,500 an hour and 6,000 a day.

The byte defaults are set on #194, approved at the same time: none a minute, 50 GB an hour and 100 GB a day.

This is clawbot's now, for smallwebwaf's manager.

Model: opus-5-5

Approved by sneak in chat on 6 November ("yes and yes"). The new default request limits are 120 a minute, 1,500 an hour and 6,000 a day. The byte defaults are set on https://git.eeqj.de/sneak/smallwebwaf/issues/194, approved at the same time: none a minute, 50 GB an hour and 100 GB a day. This is `clawbot`'s now, for smallwebwaf's manager. Model: opus-5-5
sneak was unassigned by clawbot 2026-11-06 18:37:53 +01:00
clawbot self-assigned this 2026-11-06 18:37:53 +01:00
Author
Collaborator

Plan for the implementer. Package: internal/config; no new files.

  • Change the six defaults in internal/config/config.go:
    • requests: SWWAF_RATE_LIMIT_PER_MINUTE 120, SWWAF_RATE_LIMIT_PER_HOUR 1500, SWWAF_RATE_LIMIT_PER_DAY 6000 (approved above, #193 (comment));
    • bytes: SWWAF_BYTES_LIMIT_PER_MINUTE off, SWWAF_BYTES_LIMIT_PER_HOUR 50G, SWWAF_BYTES_LIMIT_PER_DAY 100G (approved on #194 (comment)). They land here so all six defaults change in one unit; that issue then adds only its new rule.
  • Update every document that states these defaults or argues for them: the README settings table, docs/settings.md ("Request rate limits, per client" and "Byte limits, per client") and SPEC.md ("Request rate limits, per client"). Replace the old reasoning (the 20-agent fleet) with the reasoning in #193 (comment): a person reading code for an hour makes about 900 requests; a scraper at one request every 2 seconds passes the hour limit within 50 minutes; a day is four heavy hours. Say that Actions runners (about 1,800 requests an hour) and networks where many people share one address belong in SWWAF_RATE_LIMIT_EXEMPT_NETS.
  • README examples must stay true against the new defaults:
    • the example commented "Tighter limits for everyone else: a site with no API" (120/3000/30000) is now looser than the defaults; make it tighter: 60/600/3000, "a small static site";
    • the Gitea example that raises the byte limits to 16G/80G/800G "four times the default" no longer needs to: remove those three lines and their comment.
    • If docs/gitea.md or deploy/gitea/compose.yaml on next set these limits when you start, update them the same way.
  • Update the tests that pin the defaults (internal/config/config_test.go, and any in internal/smallwebwaf). No other test changes.
  • No other behaviour change. make check passes.

Model: opus-5-5

Plan for the implementer. Package: `internal/config`; no new files. - Change the six defaults in `internal/config/config.go`: - requests: `SWWAF_RATE_LIMIT_PER_MINUTE` `120`, `SWWAF_RATE_LIMIT_PER_HOUR` `1500`, `SWWAF_RATE_LIMIT_PER_DAY` `6000` (approved above, https://git.eeqj.de/sneak/smallwebwaf/issues/193#issuecomment-169687); - bytes: `SWWAF_BYTES_LIMIT_PER_MINUTE` `off`, `SWWAF_BYTES_LIMIT_PER_HOUR` `50G`, `SWWAF_BYTES_LIMIT_PER_DAY` `100G` (approved on https://git.eeqj.de/sneak/smallwebwaf/issues/194#issuecomment-169691). They land here so all six defaults change in one unit; that issue then adds only its new rule. - Update every document that states these defaults or argues for them: the README settings table, `docs/settings.md` ("Request rate limits, per client" and "Byte limits, per client") and `SPEC.md` ("Request rate limits, per client"). Replace the old reasoning (the 20-agent fleet) with the reasoning in https://git.eeqj.de/sneak/smallwebwaf/issues/193#issuecomment-169646: a person reading code for an hour makes about 900 requests; a scraper at one request every 2 seconds passes the hour limit within 50 minutes; a day is four heavy hours. Say that Actions runners (about 1,800 requests an hour) and networks where many people share one address belong in `SWWAF_RATE_LIMIT_EXEMPT_NETS`. - README examples must stay true against the new defaults: - the example commented "Tighter limits for everyone else: a site with no API" (`120`/`3000`/`30000`) is now looser than the defaults; make it tighter: `60`/`600`/`3000`, "a small static site"; - the Gitea example that raises the byte limits to `16G`/`80G`/`800G` "four times the default" no longer needs to: remove those three lines and their comment. - If `docs/gitea.md` or `deploy/gitea/compose.yaml` on `next` set these limits when you start, update them the same way. - Update the tests that pin the defaults (`internal/config/config_test.go`, and any in `internal/smallwebwaf`). No other test changes. - No other behaviour change. `make check` passes. Model: opus-5-5
Author
Collaborator

sneak, in chat on 6 November:

you can make and merge a PR instantly yourself without review to just change the rate limit values. that isn’t building anything it’s just changing a default setting.

So this PR gets no independent review. For smallwebwaf's manager and its worker: the PR changes only the default values, and their tests and the README table to match:

  • the request limits: 120 a minute, 1,500 an hour, 6,000 a day;
  • the byte limits approved on #194: off a minute, 50G an hour, 100G a day.

As soon as it is up and make check passes, the top-level manager squash-merges it into next. Do not spawn a reviewer for it.

Model: opus-5-5

sneak, in chat on 6 November: > you can make and merge a PR instantly yourself without review to just change the rate limit values. that isn’t building anything it’s just changing a default setting. So this PR gets no independent review. **For smallwebwaf's manager and its worker:** the PR changes only the default values, and their tests and the README table to match: - the request limits: 120 a minute, 1,500 an hour, 6,000 a day; - the byte limits approved on https://git.eeqj.de/sneak/smallwebwaf/issues/194: `off` a minute, `50G` an hour, `100G` a day. As soon as it is up and `make check` passes, the top-level manager squash-merges it into `next`. Do not spawn a reviewer for it. Model: opus-5-5
Author
Collaborator

Built in #200: all six defaults changed as approved (requests 120 / 1,500 / 6,000; bytes off / 50G / 100G), with the README, SPEC.md, docs/settings.md and docs/gitea.md updated to match.

Model: opus-5-5

Built in https://git.eeqj.de/sneak/smallwebwaf/pulls/200: all six defaults changed as approved (requests 120 / 1,500 / 6,000; bytes `off` / `50G` / `100G`), with the README, `SPEC.md`, `docs/settings.md` and `docs/gitea.md` updated to match. Model: opus-5-5
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/smallwebwaf#193