Skip to content

Drop the decommissioned prover's rate-limit exemption - #232

Merged
defenwycke merged 4 commits into
mainfrom
fix/218-drop-dead-prover-exemption
Sep 8, 2026
Merged

Drop the decommissioned prover's rate-limit exemption#232
defenwycke merged 4 commits into
mainfrom
fix/218-drop-dead-prover-exemption

Conversation

@defenwycke

Copy link
Copy Markdown
Contributor

Refs #218. Removes a rate-limit bypass belonging to a machine that no longer exists.

What it was

RATE_EXEMPT listed 94.237.17.228, added 2026-07-27 with the comment "exempt our own prover". It was an UpCloud box in the same range as the retired hazync-b200 (94.237.18.83) — a prover that talked straight to :8899 instead of through the web proxy, which is why it had 19 GB against that rule.

The box is gone. Measured 2026-09-08: 0 packets in 90 s against the web box's 1,690, no connection on any port, not among the GPU servers on the account, and the operator confirms there are no other servers for this project.

Why an exemption is worse than a firewall hole

A stale ACCEPT lets a stranger reach the port. A stale exemption lets them reach it without limits — the anonymous GET flood on /api/state that §7 calls the cheapest board-takedown. Provider addresses return to a pool when a box is deleted, so the exemption stops belonging to us the moment the machine does.

The file now says so, so the next person retiring a prover retires its entry with it.

⚠ I got this wrong first time

I originally called the rule stale on packet counts alone. That was bad reasoning: the address is referenced in two places and its own comment calls it "our own prover", so it was deliberate, not forgotten. A dormant counter is evidence of silence, not of decommissioning — what actually settled it was the operator's account inventory. Worth recording, because the same mistake would have removed something live.

Applied live alongside this

  • iptables ACCEPT for :8899 removed — backup /root/iptables.bak.20260908
  • this dropin installed, daemon-reload + restart — backup /root/ratelimit.conf.bak.20260908

Verified after both: public /api/meta still reachable through the web box (frontier advanced 3,644 → 3,646 across the restart), workers still crediting to G H O S T, three consecutive public GETs all 200.

For the record, since it was asked: the coordinator is not this address — it is 152.53.93.164, and is not on UpCloud at all.

#218 stays open for the rest of §7 (the nginx limit_req/limit_conn, micro-cache and TRUSTED_PROXIES items on the web box).

`RATE_EXEMPT` listed `94.237.17.228`, added 2026-07-27 as "our own prover" —
an UpCloud box in the same range as the retired `hazync-b200`
(94.237.18.83). The box is gone. Measured 2026-09-08: 0 packets in 90 s
against the web box's 1,690, no connection on any port, not among the GPU
servers on the account, and the operator confirms no other servers exist for
this project.

An entry in this list is a rate-limit BYPASS, and that is the part worth being
careful about. A firewall ACCEPT for a dead address lets a stranger reach the
port; an exemption lets them reach it **without limits** — an anonymous GET
flood on `/api/state`, which §7 calls the cheapest board-takedown. Provider
addresses go back into a pool when the box is deleted, so the exemption stops
belonging to us the moment the machine does.

The file now says that, so the next person removing a prover removes its entry
too.

⚠ I first called this rule stale on packet counts alone and was wrong to: it
is referenced in TWO places and its own comment calls it "our own prover", so
it was deliberate, not forgotten. What settled it was the operator's account
inventory, not the counter. A dormant counter is evidence of silence, not of
decommissioning.

Applied live at the same time: the matching `iptables` ACCEPT for `:8899` was
removed (`/root/iptables.bak.20260908`), and this dropin installed with
`daemon-reload` + restart (`/root/ratelimit.conf.bak.20260908`).

Verified after both changes: public `/api/meta` reachable through the web box
(frontier advanced 3,644 → 3,646 across the restart), workers still crediting
to `G H O S T`, three consecutive public GETs all 200. The coordinator is not
the address in question — it is 152.53.93.164, and is not on UpCloud at all.

Refs #218.

Claude-Session: https://claude.ai/code/session_01BGBba1FtGQjp2focJGWtjU
Follows the exemption removal in this PR; same issue (#218), same surface.

## The limiter answered 503

nginx defaults `limit_req_status`/`limit_conn_status` to **503**, and neither
the repo config nor the live one set them. 503 is the same code the board
returns during a genuine outage, so a contributor who merely burst too hard
gets an answer indistinguishable from "the board is down" — and so does anyone
diagnosing it from outside. 429 is the specific code, and clients back off on
it instead of treating the service as dead.

Measured on the live endpoint, 40 concurrent GETs on `/api/state`:

    before:  20x 200  +  20x 503
    after:   20x 200  +  20x 429

Twenty through and twenty refused, matching `burst=20` exactly — so the limiter
was working the whole time and only its vocabulary was wrong.

⚠ Applied to the **hazync locations only**, not the `http` context. The live
web box also serves `ladder_api` and `pool_api` from the same file, and a
global `limit_req_status` would have changed their behaviour too — not this
issue's business.

## §7's notes now match what is there

The stale `94.237.17.228` ACCEPT is removed, so the warning that it "should be
removed" is stale in turn. Replaced with what was done and, more usefully, the
two rules worth keeping:

- retire the `RATE_EXEMPT` entry when you retire the box — a stale ACCEPT lets
  a stranger reach the port, a stale exemption lets them reach it WITHOUT
  LIMITS, which is the flood §7 exists to stop
- do not judge an allow-rule by its packet counter alone — a dormant counter
  shows silence, not decommissioning

Verified: `nginx -t` clean before reload, nginx active after, board serving
(frontier 4,083), and the four relevant repo check scripts REAL_EXIT=0.
Live config backed up to `/etc/nginx/backups/bitcoinghost.bak.hazync-429.20260908`.

Refs #218.

Claude-Session: https://claude.ai/code/session_01BGBba1FtGQjp2focJGWtjU
@defenwycke

Copy link
Copy Markdown
Contributor Author

Second commit added — same issue, same surface. Verified §7's web-box half and fixed one thing it got wrong.

§7's web-box hardening is already deployed AND working

The issue implies this is outstanding. It is not — and I checked it fires rather than trusting that the directives are present, which is the distinction that matters here:

40 concurrent GETs on /api/state  ->  20x 200 + 20x 503
x-cache-status: HIT

Twenty through, twenty refused, matching burst=20 exactly; the 1 s micro-cache is live. nginx -t clean, and sites-enabled/ contains no backup files (the glob would load them).

But it answered 503, which is the wrong thing to say

nginx defaults limit_req_status/limit_conn_status to 503 — the same code the board returns during a real outage. So a contributor who merely burst too hard cannot distinguish "slow down" from "the board is down", and neither can anyone debugging from outside. Now 429, which clients back off on:

after:  20x 200 + 20x 429

⚠ Applied to the hazync locations only, not http. The same file serves ladder_api and pool_api, and a global setting would have changed those services too — outside this issue's scope.

RUNBOOK caught up

The warning that the stale ACCEPT "should be removed" is itself stale now it is removed. Replaced with what was done plus the two durable rules: retire the RATE_EXEMPT entry when you retire the box, and don't judge an allow-rule by its packet counter alone.

Live config backed up to /etc/nginx/backups/bitcoinghost.bak.hazync-429.20260908; board serving throughout (frontier 4,083).

@defenwycke
defenwycke merged commit 482743a into main Sep 8, 2026
6 checks passed
@defenwycke
defenwycke deleted the fix/218-drop-dead-prover-exemption branch September 8, 2026 07:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant