Skip to main content
A host a proxy serves can be switched to a status: maintenance, blocked, moved, and so on. Every proxy serving the host then answers its visitors with a status page instead of sending them to the backend, with the right HTTP status code and, where it fits, a Retry-After header. The page shows:
  • the error code, a title and a message
  • the chain You → Proxy → Destination, with how each hop is doing (for maintenance: your browser connected, the proxy connected, the site maintenance)
  • Try again and More information buttons
  • a request ID and the time, and “Powered by DNZ”
It is one self-contained page (no fonts, scripts or images from elsewhere) in light and dark, and search engines are told not to index it. Every kind of proxy shows them: dnz-proxy nodes render the page themselves, a Caddy answers with it straight from its configuration, and a Traefik fetches it from DNZ. See How each proxy shows it.

Which names can have one

Plain DNS can’t show a page: it only hands out addresses. So only names a proxy serves can have a status:
  • the name of a proxied record (see Proxied records), or
  • a router’s host on one of the proxies (see Routing).
DNZ refuses a status for a name no proxy serves, and says so. *.example.com covers one label below example.com (app.example.com, not a.b.example.com). When a host has a status of its own and a wildcard covers it too, its own status wins. A host has at most one status.

Statuses

Each status can get its own title and message instead of the usual ones (up to 120 and 2000 characters; a message keeps its line breaks), and a link for the More information button, for example your status page or an announcement.

Setting one

1

Open Status pages

Go to DNS → Status pages and click New status page. Or, in a zone, open a proxied record and pick Status page…: the same dialog opens with the record’s name filled in.
2

Pick the host and the status

The host field offers the names a proxy serves, with the proxies serving each.
3

Fine-tune it

Optionally give a title, a message, a schedule, allowed addresses and a link. For Moved, give the new address and whether to keep the path. The preview shows the page as visitors will see it.
4

Save

Every dnz-proxy node serving the host shows the page within seconds.
The list shows each status with its state (active, scheduled, ended, off), its window and the proxies serving it. A status can be turned off without removing it, and turned on again later with everything it had.

Schedule and Retry-After

A status is on from the moment it is saved until it is turned off, unless it has a window:
  • Starts at: it waits until then (scheduled), and visitors reach the backend as usual.
  • Ends at: it stops on its own (ended). Until then, the page shows Expected back with that time, and Retry-After counts down the seconds to it.
Without an end time, Retry-After is only sent for rate_limited (60 seconds). Schedules are evaluated by the proxy nodes themselves, so a status starts and ends on time even while a node can’t reach DNZ. A change made in DNZ reaches every dnz-proxy node within seconds.

Letting some visitors through

Allowed addresses (IPs and CIDRs, up to 100) reach the backend as usual, for example your office network, or the team checking the site after maintenance:
The visitor’s address is the one dnz-proxy sees, or the one a load balancer in front of it hands over (the entry point’s PROXY protocol from and Trusted forwarders, see Entry points).

Moved

moved needs the new address (https://new.example.com). Visitors get a 301 with Location: <new address>. With keep path, the path and query come along: https://old.example.com/docs?page=2 goes to https://new.example.com/docs?page=2.

How each proxy shows it

The statuses come with the configuration DNZ pushes to the nodes, within seconds of a change. Each node renders the page itself and starts and ends scheduled statuses on its own clock. The page is checked after the router matches and before its middlewares, so Let’s Encrypt’s HTTP-01 checks still get through.
Each status becomes a route in front of the site’s routes that answers with the page itself (static_response, one each for HTML, JSON and text). Allowed addresses are left out with a not remote_ip matcher. The request ID and time come from Caddy ({http.request.uuid}, {time.now.http}), and Moved with keep path sends visitors to <new address>{http.request.uri}. Caddy fetches its configuration every 10 seconds, so a status (or the start or end of its window) shows up within that.
Each status becomes a router with a higher priority than any of DNZ’s for the host, on the same entry points and with the same TLS. It sends visitors to DNZ’s /api/proxy/status-page, at the address the Traefik reached DNZ on, unless their address is allowed (!ClientIP(...)). DNZ renders the page there. Traefik polls every 5 seconds by default, and it has to reach DNZ’s HTTP port, which it already does to poll.
Only names DNZ’s own routers serve can be put in front of: a name a Traefik routes with its own routers (Docker labels, Kubernetes, files) can’t have a status page.

Automatic pages for the proxy’s own failures

dnz-proxy also shows a styled page when it can’t get an answer from the backend, for every host and with no setup: These can’t be set by hand.

HTML, JSON or text

The page comes in the form the visitor asks for with Accept:
  • Browsers (text/html) get the HTML page.
  • API clients (Accept: application/json) get JSON. until, location and link are only there when they are set:
  • Everything else gets plain text.
Every answer has Cache-Control: no-store, X-Robots-Tag: noindex and X-Request-Id, so a cache never keeps the page after the status is lifted. Proxy → Analytics counts these visits under Firewall rules as status maintenance (and so on), and the request log shows them.

Who can set one

  • Superadmins manage every status.
  • Others manage statuses of hosts in zones where they have records.write, and see those of zones they can view (zones.read).
  • A host in none of DNZ’s zones (a router’s host for a domain DNZ doesn’t hold) is superadmin-only.
API tokens follow the same rule with their own permissions and zones. Every change is in the audit log as status_page.create, .update, .enable, .disable or .delete.

Next steps

Status pages in the CLI

Set, schedule and lift statuses from the terminal.

Status pages API

The endpoints and the fields of a status.