Skip to main content
A route’s Rate limit (requests a second per visitor, with a burst) and an in-flight limit (requests in progress at once per visitor) answer 429 when one visitor sends too much. A DNZ Proxy records every refusal, so Proxy → Rate limits shows who hit which limit, from where and on which route, as the WAF page does for attacks.

See what was refused

Open Proxy → Rate limits. Pick a proxy (or all of them) and a span.
  • Totals: refused by a rate limit, by an in-flight limit, the addresses, and addresses banned for hitting limits.
  • Over time, the map, the busiest limits (with their setting, like rate 5/s, burst 10, and their routes), addresses, paths, countries and hostnames.
  • Refused requests: one row per request, newest first. Filter by address, hostname, limit, rate or in-flight, or a path. Open a row for the user agent, referer, node and request ID.
  • Banned for limits, with Unban.
Block and Ban work as on the WAF page. Before you use them, look for two marks:
  • Shared address: a mobile carrier’s network, or several browsers from one address. Many people may be behind it, and a block would refuse them all.
  • Forwarder warning: most refusals come from a private address, one of your nodes, or a hosting or CDN network. The limit is probably counting the load balancer or CDN in front of DNZ Proxy, not your visitors. Add it to the entry point’s Trusted forwarders, and the limit sees each visitor again.
Proxy → Analytics shows the same numbers beside the WAF section, and its request log has a Rate limited filter. On the home page, Overview → Proxy says how many of the blocked requests a rate limit refused.
Blocked numbers go up after you upgrade wherever rate limits already refuse traffic: before, those refusals weren’t counted anywhere.

Set limits on routes

The Settings tab lists every route with its limits and what each refused in the last 24 hours.
  • Edit or Add opens the route dialog.
  • Suggest proposes a rate and burst from the busiest address on the route in any ten minutes of the last day: three times its average then. It is an average over ten minutes, not a peak.
  • Add a limit to routes: pick routes and set one limit on all of them. Each route’s history keeps a version.
Starting points: a login or password reset, a few requests a minute per address. A whole site, some tens a second, with a burst of twice that. In the route dialog, a rate limit on a DNZ Proxy also has:
  • Log only: refuse nothing, and count and list what the limit would refuse. Try a number first.
  • Never limit these addresses: your monitoring, your office, partners.
  • Count per: what makes one visitor. See What counts as one visitor.

Ban addresses that keep hitting limits

Off by default. On, a limit’s refusals count towards the proxy’s Bans that expire (its DNZ Proxy settings) (N blocks within M minutes), as the WAF’s blocks do. Turn it on under Proxy → Rate limits → Settings, or with dnz proxy settings edge --ban-rate-limited on. Leave it off when a limit is keyed by a header, or when many people share one address (an office behind NAT): it would ban real people.

Soft and hard bans

A banned address is refused one of two ways. Pick it under Proxy → Rate limits → Settings → Bans, or in the proxy’s Bans that expire: A ban you make by hand (the block dialog on the WAF page or this page) is soft or hard by itself. Trusted forwarders (a CDN, a load balancer) and private addresses are never hard-banned: they get the page.

Drop hard bans in the kernel firewall

Off by default. On, each node also drops hard-banned addresses in its own nftables table, so their packets never reach the proxy. It helps only against visitors who connect directly, not those behind a CDN. Each node needs nftables and the right to change the firewall:
In Docker the node can’t write the firewall itself, so a small sidecar beside it does (bridge networking works, the release image stays as it is). Add it beside the node’s service; it touches only the node’s own table and removes it when stopped. The settings page fills in your service and volume names:
The image is nicolaka/netshoot v0.14, pinned by digest (about 850 MB, pulled once). The settings page lists each node: how many addresses it drops, or why it can’t.

Connections per address

Each HTTP or HTTPS entry point can cap how many connections one address keeps open at once. Past it, a new connection is closed before TLS. No limit by default. Set it on the proxy’s Ports (the entry point dialog), or dnz proxy entrypoints edit edge websecure --max-connections-per-ip 50. Trusted forwarders and private addresses are never limited; a browser opens about 6 connections per site.

Under attack during a spike

Off by default, per proxy. On, a hostname whose traffic spikes and whose origin struggles (5xx answers on at least 5% of its requests) gets the browser check (Under attack) until the spike is over, then it goes off by itself. A launch or a newsletter your origin handles changes nothing.
1

Turn it on

Proxy → Rate limits → Settings → Under attack during a spike, or dnz proxy flood set edge --on.
2

Mark routes that must never be checked

A browser check answers API clients and webhooks with 403. In the route dialog, under Stop attacks, switch on Never turn on Under attack by itself. The settings list routes that look like an API.
Exempt under the setting lists the addresses and user agents that never see this check: your monitoring, your office, partners. DNZ’s own uptime checks always go through. A route with its own Under attack keeps its own check and its own exempt lists. DNZ decides once a minute from every node’s counts, so it acts one to two minutes after a flood starts. A hostname stays checked at most 6 hours in a row. Each start and end is an incident and a notification (Under attack on by itself), and shows in What changed?. End one early with End on the page, or dnz proxy flood end edge shop.example.com: it stays off for that hostname for an hour.

Alerts

Under Settings → Notifications → Proxy alerts:
  • Traffic spike (on by default): requests on a hostname, blocked or not, rise sharply. The message says how many got a 5xx answer and whether they come from a few addresses or many.
  • Attack spike counts what rate limits refuse as blocked, unless you switch Count rate limits off.
See Notifications.

What it costs

A request no limit refuses costs nothing more: the counting happens only for a refused request, and the automatic Under attack is in no route while it is off. Details in Proxy benchmarks.

What counts as one visitor

Each address is one visitor unless you say otherwise. On a DNZ Proxy, on a full DNZ and on a reverse proxies only one, a limit can count per any of these, and up to four together: For example, cookie:session with path gives each signed-in person a budget per page, and header:X-Api-Key gives each API key its own. Use Count per in the route dialog, Or count per these together on a rate limit or in-flight middleware, or the terminal:
Terminal
  • A request without the cookie, header or parameter counts as its address, for that part only. Visitors without a cookie never share one budget.
  • Visitors choose what they send, and each new value is a new budget. To stop an attacker, keep a limit per address as well, with a higher number. A cookie or header is for treating people behind one address fairly.
  • With several nodes, each counts for itself unless the limit shares Redis.
  • A ban for hitting limits still bans the address.

Traefik, Caddy and Nginx

They don’t record refusals for this page. Log only and Never limit these addresses are DNZ Proxy only: on Traefik and Nginx the limit holds for everyone, and the proxy’s page says so. Caddy has no rate limit built in, so the limit is left out there, with a warning. Count per: Traefik takes one request header or the hostname. A request without that header doesn’t fall back to its address there. Anything else counts per address on Traefik and Nginx, with a warning.