Cloudflare Health Checks: Origin Monitoring and Edge Probes
Back to blog

Cloudflare Health Checks: Origin Monitoring and Edge Probes

Updated 9/24/2026 · Published 9/24/2026 · 4 min · DevOps

I have lost sleep over web services crashing silently behind a reverse proxy, only finding out half an hour later when a user emailed me to complain. That is the main drawback of running behind Cloudflare: from the outside, DNS resolves fast and the edge network serves a clean error page with Error 521 (Web Server is Down) or Error 522 (Connection Timed Out). The visitor sees the downtime, but your server never receives a single request.

To avoid relying on user reports, I run automated probes. Cloudflare offers a native feature called Health Checks. In this guide, I cover how it works, what the plan limits look like, and how I built a free alternative using Cloudflare Workers and a static Nginx endpoint.


How Cloudflare Health Checks work#

Unlike running an uptime script on the same VPS or pinging from a single external box, Cloudflare Health Checks run from edge datacenters across the globe. They send scheduled requests directly to your origin IP or hostname.

The main benefits:

  1. Individual origin monitoring: you do not need the Load Balancing add-on. You can point probes at a single standalone VPS or dedicated server.
  2. Granular parameters: specify protocol (HTTP, HTTPS, or TCP), port, exact URI path (such as /healthz), HTTP method, and expected status codes (200).
  3. Regional latency metrics: the Health Check Analytics dashboard breaks down latency by region, showing connectivity bottlenecks before total failure.
  4. Clear failure reasons: when an origin fails, logs specify whether it was a connection timeout, connection refused, TLS handshake error, or unexpected HTTP code.

Plan tier limits: Standalone vs Passive Monitoring#

When opening the Cloudflare dashboard to set up an active probe, you run into plan restrictions:

FeatureFree PlanPro PlanBusiness / Enterprise
Standalone Health Checks0 included10 included50 to 1,000 included
Minimum intervalN/A60 seconds10 to 15 seconds
Passive Origin MonitoringYesYesYes
Email notificationsYesYesYes

Active, standalone Health Checks require at least a Pro plan ($20 to $25 per month). The Free plan includes zero standalone active checks.

What the Free plan includes: Passive Origin Monitoring#

Even without a paid subscription, you can use Passive Origin Monitoring. Instead of sending synthetic requests every minute, Cloudflare monitors real traffic. If the rate of 521, 522, or 524 errors spikes above normal levels, you get an automated alert email.

To enable this:

  1. In your global account menu, go to Notifications.
  2. Click Add and search for Passive Origin Monitoring.
  3. Select your zone and enter the destination email.

Setting up a lightweight Nginx endpoint (/healthz)#

A common mistake in uptime monitoring is pointing probes to the root path (/) or to a heavy application route (like WordPress index.php). Hitting those routes every 60 seconds forces the server to boot runtimes, query databases, and waste CPU cycles.

To avoid this, I set up a static response block in Nginx:

# Ultra-lightweight static health check (no PHP or database load)
location = /healthz {
    access_log off;
    default_type text/plain;
    return 200 "OK\n";
}

This setup provides two advantages:

Test the syntax and reload:

nginx -t && systemctl reload nginx

The free alternative: Worker with Cron Trigger#

If you are on the Free tier and need active checks every 60 seconds without waiting for real visitors, the cleanest solution is a Cloudflare Worker with a Cron Trigger.

The Worker runs on the Cloudflare edge, makes an HTTP GET request to /healthz, and sends a webhook alert to Discord or Slack if the server is unreachable.

Worker implementation (worker.js)#

export default {
  async scheduled(event, env, ctx) {
    const TARGET_URL = "https://perciocastelo.com.br/healthz";
    const WEBHOOK_URL = env.ALERT_WEBHOOK_URL;
    const TIMEOUT_MS = 5000;

    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);

    try {
      const response = await fetch(TARGET_URL, {
        method: "GET",
        headers: { "User-Agent": "Cloudflare-Worker-Probe/1.0" },
        signal: controller.signal
      });
      clearTimeout(timeoutId);

      if (response.status !== 200) {
        await notifyAlert(WEBHOOK_URL, `ORIGIN DOWN: HTTP status ${response.status}`);
      }
    } catch (err) {
      clearTimeout(timeoutId);
      const isTimeout = err.name === "AbortError";
      const errorMsg = isTimeout 
        ? `TIMEOUT: Origin took longer than ${TIMEOUT_MS / 1000}s to respond.`
        : `NETWORK ERROR: ${err.message}`;
      
      await notifyAlert(WEBHOOK_URL, `CRITICAL ALERT: ${errorMsg}`);
    }
  }
};

async function notifyAlert(webhookUrl, message) {
  if (!webhookUrl) return;
  await fetch(webhookUrl, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      content: `[Origin Monitor] ${message} - ${new Date().toISOString()}`
    })
  });
}

Scheduling the probe in wrangler.toml#

To run the check every minute:

name = "origin-health-probe"
main = "src/index.js"
compatibility_date = "2026-09-24"

[triggers]
crons = ["* * * * *"]

At one run per minute, you generate about 43,200 requests per month, well below the 100,000 free requests per day included with Cloudflare Workers.


Pro plan setup (Native Dashboard)#

For zones running on Cloudflare Pro or Business:

  1. In the zone dashboard, open Traffic and click Health Checks.
  2. Click Create Health Check.
  3. Configure the probe:
  1. Save and proceed to the notifications step to attach your email or webhook alerts.

Wrap up#

You do not need to spend $20 a month just to know when your server goes down. Cloudflare's passive monitoring handles live traffic for free, and a lightweight Worker with a Cron Trigger gives you active, 60-second checks with instant notifications straight to your phone.

Was this article helpful?

Leave a quick reaction to help prioritize future technical guides:

CC BY-NC

This post is licensed under CC BY-NC.

Comments

Join the discussion below.

0 comments