Skip to main content
The abuse defense turns away clients that hit an app too hard or that you know are bad, before the request reaches the container. It is set per app, covers every proxied domain of the app, and starts in a mode that blocks nothing so you can see its effect first. It sits in front of the per-domain abuse shield and the instance firewall. Use the shield for per-domain concurrency and body limits, and this for a per-app rate with a safe rollout.

What it checks

The deny checks run first, so a denied client never spends a rate token. The rate limit is a token bucket per client address: rps is the refill rate, burst the bucket size. A rate of 0 turns the limit off and leaves the lists.

Modes

Move from log_only to enforce once the replay shows nothing you want to keep would be blocked. The dashboard only offers enforcing after the replay for the current settings has loaded.

Client address

The client address is the one the access log and firewall use: the TCP peer, unless it is a configured trusted proxy, in which case the forwarded header is read from the right, skipping trusted hops. A forwarded header from any other peer is ignored, so a client cannot dodge a limit or frame someone else by sending X-Forwarded-For. Behind a proxy that hides client addresses and with no trusted proxies set, the status shows ClientIPHidden: every visitor would share one limit.

Status

Each policy reports a condition with a reason: Enforcing, LogOnly, Off, NoRoutes (the app has no proxied route, for example a static site or a stopped app), ClientIPHidden, InvalidPolicy or Pending (waiting for the next ingress pass).

Fail open

The defense never takes an app down. If the policy store cannot be read, the stored policy is invalid, or evaluating a request panics, the request is served and a fail_open counter goes up. The dashboard and apps abuse get show it.

Counters

Per app, per window, in the traffic view and metrics: allowed, would_block and blocked by reason (rate_limit, deny_cidr, deny_user_agent, missing_user_agent), and fail_open. Metric names start with http_abuse_.

Replay before you enforce

The replay runs the last minutes of the control plane’s in-memory access log through a draft policy and reports how many requests it would have blocked and which clients were hit most. It reads memory only and changes nothing. Client addresses and User-Agents are kept in memory for this and are never returned by the access log API or written to disk, so the replay covers only what the log still holds (a restart empties it) and needs the read:sensitive ability.
Open the app, then Traffic. The Abuse defense card shows the mode, the per-client rate (prefilled from the app’s recent peak), the block lists and a live preview of what the draft would have blocked.

Limits and tuning

All caps and defaults come from the environment, never from code. Every variable is optional. Memory is bounded by APP_ABUSE_MAX_TRACKED_CLIENTS per app. When a shard is full, an arbitrary tracked client is dropped, so a flood of distinct addresses cannot grow memory. Static sites served directly by the ingress are not covered yet.
Last modified on October 23, 2026