← All guides

How to allow Pingdomain through the Cloudflare WAF

A skip rule that allows your own uptime checks through the Cloudflare WAF, without opening a hole anyone else can walk through.

What you are matching on

Every check we send carries these, and they are stable:

Pingdomain/2.0 (+https://www.pingdomain.io; monitoring)

We also publish an Ed25519 key directory for RFC 9421 HTTP Message Signatures and are going through Cloudflare's bot verification programme. Until that registration is approved, checks are not signed that way — a signature a verifier cannot check against an approved key list looks like forgery and gets you blocked harder, so we keep it switched off until it helps. When it is live, "verified bots" becomes the simplest rule of all. Details are on the bot page.

Step 1 — turn off the blanket block first

Go to Security → Bots. If "Block definitely automated traffic" is on, no WAF skip rule below will help, because the bot module runs before your custom rules for some products. Set it to allow, or scope it so it does not cover the path you monitor.

Step 2 — add a skip rule

Go to Security → WAF → Custom rules and create a rule with the action Skip, ticking the components you want bypassed — typically "All remaining custom rules", "Rate limiting rules" and "Super Bot Fight Mode". Use the expression editor and paste:

(http.user_agent contains "Pingdomain/" and http.request.uri.path eq "/health")

Scope it to the path you monitor. That is the whole trick. A user agent can be claimed by anyone, so a rule matching only on it is a hole across your entire site — but a rule that only exempts the one health endpoint you point the monitor at is worth almost nothing to an attacker and everything to you.

If you monitor several paths, match a prefix instead:

(http.user_agent contains "Pingdomain/" and starts_with(http.request.uri.path, "/status/"))

Step 3 — verify at your origin, if it matters

For an endpoint that must not be exposed at all, do not rely on the WAF: check the signature in your own application and return 404 to everyone else. Verification is a dozen lines, and the secret never leaves your server.

// Node.js — verify x-pingdomain-signature
import { createHmac, timingSafeEqual } from 'node:crypto';

function verify(header, monitorId, secret) {
  const parts = Object.fromEntries(
    header.split(',').map((p) => p.split('=')),
  );
  const age = Math.abs(Date.now() / 1000 - Number(parts.t));
  if (!Number.isFinite(age) || age > 300) return false; // replay window

  const expected = createHmac('sha256', secret)
    .update(`${parts.t}.${monitorId}`)
    .digest('hex');

  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1 ?? '');
  return a.length === b.length && timingSafeEqual(a, b);
}

The timestamp is inside the signed value, which is what lets you reject a replayed header rather than accepting it forever.

Step 4 — confirm it worked

Open the monitor and wait one interval. A check that was being challenged goes from a 403 at 8 ms to a 200 at whatever your origin actually takes — and the difference between those two numbers is usually the clearest proof that the rule matched.

Still blocked? The response body is kept for failed checks. Read it: it will name the product that rejected the request, which is often a second layer nobody remembered was on.

Checks you can actually allow through

An honest user agent, a signature you can verify, and an error message that says which protection blocked it. Three monitors are free.

Get started — free