# Block page

> Choose what a blocked visitor sees: an nginx- or Apache-style error, a generic page, OpenWAF's page or your own HTML, and the Server header.

When the edge blocks a request with an HTML answer (IP, country, feed or WAF blocks, shields, rate limits), it renders the page set by `block_page_mode`:

| `block_page_mode` | Dashboard | Page |
|---|---|---|
| `branded` (default) | Branded page | OpenWAF's page: "Access Denied" (or "Too Many Requests" for 429) with the status code and the reason, such as `WAF Block` or `IP Rule`. |
| `nginx` | Looks like an nginx error | Identical to stock nginx error pages. |
| `apache` | Looks like an Apache error | Like Apache httpd's default error pages. |
| `generic` | Generic page | A minimal page with no branding. |
| `custom` | Custom HTML | Your HTML in `block_page_html`. |

## Custom HTML

`block_page_html` holds up to 256 KiB of self-contained HTML. The edge replaces these placeholders:

| Placeholder | Value |
|---|---|
| `{{.Status}}` | Status code, e.g. `403`. |
| `{{.StatusText}}` | Status text, e.g. `Forbidden`. |
| `{{.Reason}}` | Short reason, e.g. `WAF Block` (HTML-escaped). Never contains request data. |

```sh
openwaf-cloud ctl zones set example.com block_page_mode=custom \
  block_page_html:='"<!doctype html><title>{{.Status}}</title><h1>{{.Status}} {{.StatusText}}</h1><p>{{.Reason}}</p>"' \
  --reason "Custom block page"
```

If `block_page_mode` is `custom` and the HTML is empty, the nginx-style page is used.

## Server header

Blocked responses and every response from your origin carry `Server: nginx` unless you set `fake_server_header` to another value (empty = `nginx`). See [Edge responses and headers](https://developers.openwaf.dev/waf/responses/#response-headers).

In the dashboard both are under **Security → Firewall → Advanced**: **Block page**, **Custom block page HTML** and **Server header**.
