Skip to main content
A route’s Web application firewall checks every request against ready-made rules for well-known attacks: SQL injection, cross-site scripting (XSS), path traversal, command injection, Log4Shell, attack tools and the like. A DNZ Proxy blocks a match with a 403 page, or only logs it, before your servers see the request. It is off until you turn it on for a route, and it needs a DNZ Proxy. The Firewall holds your own rules; these are DNZ’s, the same for every route. For one known vulnerability in an app you can’t upgrade, see Shields.

Turn it on

1

Open the route

On the proxy’s page, open the route (Routes → the route).
2

Switch on Web application firewall

Pick Block attacks or Log only, and a Sensitivity. Medium is the usual choice.
3

Save

Every node has it within seconds.
Or from the terminal:
Not sure it suits your site? Start with Log only (--waf log): nothing is blocked, and every match shows in Analytics and the request log. Switch to Block attacks once only attacks show up.

What it checks

  • the path,
  • every query parameter, its name and its value,
  • the User-Agent and Referer headers and the cookies’ values.
Each is decoded first, the way attacks hide: percent-encoding (twice), + as a space, HTML entities such as <, and SQL comments (UNION/**/SELECT). Case doesn’t matter.
The request body isn’t checked yet: a form POST or a JSON body goes through unseen. For uploads, Upload limits check what multipart bodies may hold, and your own Firewall rules can refuse methods or paths that should take no body at all.

Sensitivity

Each rule starts at one sensitivity and runs at every higher one: dnz proxy waf rules lists every rule with what it catches.

Block or log only

  • Block attacks (default): the visitor gets an Access blocked page with the 403 status, saying the site’s firewall stopped the request, and a request ID to send you (HTML, JSON or text, like the status pages). The request never reaches your servers.
  • Log only: the request goes on as usual; the request log notes log waf:<rule>.

See what it matched

  • Proxy → WAF: everything in one place, with a world map of where attacks came from, each event, an address’s place and network, blocking and one-click exceptions. See The WAF page.
  • Proxy → Analytics → Web application firewall: blocked and logged requests, over time, the rules that matched (SQL injection · sqli-union, Blocked or Logged), and the addresses and paths it matched most. Click an address or a path to show its requests in the request log. It follows the page’s proxy, hostname and time range.
  • The Routes list: the WAF chip says what it did on the route’s hostnames in the last 24 hours, such as WAF · 12 blocked or WAF · log only · 3.
  • The request log (Proxy → Analytics) shows the rule on each line, such as WAF blocked · SQL injection · sqli-union. Open the line to see what the rule catches.
  • Analytics’ Firewall rules list counts the rules that matched; blocked requests count as blocked.
  • dnz proxy analytics prints the blocked and logged counts with the top rules and addresses.
  • dnz proxy routes waf-hits edge lists matches since each node started, per rule and action.
  • Prometheus: dnz_proxy_waf_hits_total{proxy, node, middleware, rule, action}, and for coverage and the page’s blocks dnz_proxy_waf_routes{proxy, state} and dnz_proxy_waf_page_blocks{kind}.
  • AI assistants: the MCP tools proxy_waf_rules, proxy_waf_hits and, with write access, set_waf.
Thinking of a higher sensitivity? Preview it first: the extra rules only count, and the page says what they would also have stopped.

Exceptions

Under Exceptions in the route dialog: Paths are plain prefixes: /admin also covers /administrator. Skipping one rule is safer than turning the whole firewall off.

When a real visitor gets blocked

1

Find the request

In Proxy → WAF, find the event (filter by the address or hostname) and use Not an attack…: it adds the exception for you (The WAF page). Or in Proxy → Analytics → Web application firewall, click the visitor’s address (or the path) to show its requests in the request log, or filter the log by the hostname and the address. The line names the rule; Copy rule id copies it.
2

Pick the narrowest exception

Skip the rule when a normal page trips it, the path when one page takes code or markup on purpose, or the address when it is your own tool.
3

Add it

In the route dialog (Web application firewall → Exceptions), or:
4

Watch

Not sure what else it stops? Switch the route to Log only for a while, check the hits, then go back to Block attacks.

Where it runs

It runs right after the route’s address list and your own Firewall, so your rules decide first. A Firewall Allow rule doesn’t skip these rules: use Never check these addresses instead. The rules are compiled once on each node (per sensitivity) and shared by every route. A request that matches nothing, nearly all of them, costs one pass of the rules over what it sent.

What it costs

Next to nothing for ordinary requests (−1 to −3% requests a second on one CPU); a request carrying many query parameters and cookies costs about 13 µs more CPU (−13%). +2.3 MiB of memory per node at Medium, +4.2 MiB at High. Details in Proxy benchmarks.

Traefik and Caddy

Traefik and Caddy proxies have no web application firewall: a route with it is refused there. A route saved on several proxies gets it on the DNZ Proxies only.