Traffic resilience guide

Operate Cloudflare Load Balancing Safely

Define health and capacity before steering traffic, then prove both the preferred and degraded paths without making the only healthy production origin unavailable.

Published
Updated
Reading time
22 min read
On this page

Cloudflare Load Balancing sits directly in the request path, so every pool, monitor, and steering decision configured here becomes a signal that whoever is on call must trust immediately, not just at demo time — the same discipline a managed edge-orchestration layer applies when it runs load balancing across many customers and providers at once.

Overview

Outcome and Acme Shop scenario

Outcome

Acme Shop will create independently operable EU and US pools, attach a non-mutating monitor, and validate a proxied Layer 7 hostname before exposing a small production change. Operators will know whether they are testing request-level proxy routing or DNS-only answers, what caching does in each mode, and how to restore the prior steering configuration.

Running scenario

shop.acme-shop.example is Acme Shop's public storefront. Its EU pool is the preferred destination and the US pool is a capacity-tested fallback. The /healthz endpoint checks the web process and required catalogue dependency, but does not place orders, change inventory, or warm expensive caches.

Acme Shop proxied and DNS-only load balancing
  1. Proxied Layer 7

    Cloudflare routes the HTTP/S request to a healthy EU or US pool; Cache, WAF, and Workers can participate.

  2. DNS-only answer

    Cloudflare returns the selected endpoint address; a direct endpoint receives the subsequent client connection after resolver caching.

  3. Endpoint proxy status

    A selected proxied CNAME endpoint returns a Cloudflare address, so its subsequent HTTP request can still be proxied. A direct, non-proxied endpoint cannot use Cloudflare HTTP cache, WAF, or Workers.

  4. Zero-downtime retry

    A proxied request that fails against one origin with a 521-526 edge error can retry once against another healthy origin in the same pool before normal steering and fallback logic applies.

A proxied load balancer makes Layer 7 routing decisions at Cloudflare. DNS-only behavior depends on resolver caching; whether the subsequent HTTP request is proxied also depends on the selected endpoint's proxy status.

Cloudflare Load Balancing can route proxied HTTP/S traffic at Layer 7 to healthy origin pools. When the load balancer is DNS-only, it returns selected endpoint addresses in DNS answers. A direct, non-proxied endpoint then receives the client connection; a selected endpoint that is a proxied Cloudflare CNAME can still proxy the subsequent HTTP request. Neither mode is an instant, universal traffic switch: monitor cadence, health interpretation, origin capacity, and, for DNS-only selection, recursive DNS caching and connection reuse affect what users experience. Operate it as a traffic-management control plane with explicit health semantics and tested degradation behavior.

This tutorial gives DevOps and platform engineers a conservative production workflow. It does not assume that health checks prove application correctness or that failover will occur within a fixed time.

Prerequisites

Prepare the following before creating a production load balancer:

  • A Cloudflare plan and account configuration that includes the Load Balancing capabilities you intend to use. Confirm entitlement and current product constraints in Cloudflare Load Balancing. Several options used later in this guide — the widest monitor regions, least outstanding requests, and pop_pools geo overrides — are Enterprise-only; verify availability first.
  • At least two independently operable origin pools where the service design requires failover. A second pool that shares the same failure domain is not meaningful resilience.
  • An origin endpoint suitable for synthetic health checking, with documented authentication requirements, expected status code, body, and dependency scope.
  • Capacity data for each origin pool, including normal load, safe sustained load, burst behavior, connection limits, autoscaling delay, and database or downstream limits.
  • Access to Cloudflare DNS and Load Balancing configuration, plus origin metrics, logs, and a coordinated change window.

Stage 1: Define the Route and Origin Health Checks

Start with the user-facing hostname and the exact request path that is being protected. Decide whether the load balancer answers the apex, a subdomain such as api.example.com, or a dedicated service hostname. The hostname must have Cloudflare DNS configuration compatible with the load balancer setup.

Then define what “healthy” means. A monitor verifies the response seen from Cloudflare’s monitoring infrastructure; it does not prove that every application journey, user location, or dependency is healthy. Cloudflare documents monitor fields and status evaluation in Monitors.

A useful health endpoint should:

  • Be fast and unauthenticated from the monitor’s perspective, or use the monitor’s supported request configuration deliberately.
  • Validate the dependencies whose loss should trigger traffic movement, without making the check so broad that a non-critical dependency causes unnecessary failover.
  • Return the configured expected status and, when used, expected response body consistently.
  • Avoid mutating data, warming expensive caches, or creating meaningful load at the monitor interval.

Document route semantics separately from health semantics. A 200 response from /healthz does not guarantee that every route, tenant, authentication flow, or write operation is usable.

How Cloudflare decides an origin health check has failed

Origin health checks run from several vantage points at once, not one. Probes originate from the data centers in the monitor's configured Health Monitor Region — three data centers per region by default — and Cloudflare applies a majority rule twice: a region is healthy when most of its probing data centers pass, and the endpoint is healthy when most participating regions agree. Enterprise accounts can widen this to "All Regions" or "All Data Centers," which some steering policies require outright, but wider coverage also multiplies request volume against the health endpoint; recompute the endpoint's request rate rather than assuming the original "cheap and side-effect-free" budget still holds once every data center participates.

Monitor consensus is not the same as failover readiness

Cloudflare applies a majority rule within each monitoring region and again across regions. The service owner must separately prove that the selected pool can absorb traffic.

Download:PNGSVG

A mismatched Host header, TLS SNI, or follow-redirects setting is a common cause of a monitor reporting unhealthy while a direct request from an engineer's terminal succeeds — the monitor and production traffic are not, in that case, testing the same request.

Stage 2: Create Pools With Capacity Boundaries

A pool groups origins and associates monitor behavior and origin metadata. Create a pool for each traffic destination or failure domain, then add origins with the correct address, port, weight, and enabled state. Use Pools as the configuration reference.

For each pool, record:

  • The pool’s intended role: primary, regional primary, standby, maintenance, or evacuation target.
  • The origins it contains and shared dependencies they rely on.
  • Healthy and unhealthy monitor behavior, including the endpoint, method, expected response, timeout, interval, retries, and consecutive-down criteria.
  • Safe receiving capacity for traffic transferred from another pool.
  • The origin-side signal that tells operators the pool is near saturation.

Do not size a standby pool only for its normal trickle of traffic. If it may receive failover traffic, validate its ability to accept that traffic and account for autoscaling time, connection pools, databases, third-party quotas, and cache cold starts. Cloudflare can choose a pool according to configuration, but it cannot create origin capacity.

Acme Shop later adds a third pool, acme-apac-secondary, to trial geolocation steering toward APAC customers without committing that region to full production traffic. Even a trial pool needs its own monitor, a documented capacity ceiling, and an explicit enabled state; an origin left enabled with no capacity review can absorb real traffic the moment a steering change activates it.

Acme Shop monitor and pool under review

This representative API shape captures the values reviewers need to compare: the endpoint is read-only, the expected response is explicit, and the fallback pool is not enabled until its capacity test passes. Use a non-production or approved production monitor endpoint and the current Cloudflare API schema for the account; do not place API credentials in this configuration or terminal history.

{
  "monitor": {
    "type": "https",
    "method": "GET",
    "path": "/healthz",
    "port": 443,
    "interval": 60,
    "timeout": 5,
    "retries": 2,
    "expected_codes": "200",
    "expected_body": "ok"
  },
  "pool": {
    "name": "acme-eu-primary",
    "monitor": "<reviewed-monitor-id>",
    "origins": [{
      "name": "acme-eu-web-1",
      "address": "198.51.100.20",
      "enabled": true,
      "weight": 1
    }]
  }
}

The address is a documentation-only TEST-NET value. Use DNS names or private connectivity where the architecture requires it, validate origin TLS, and restrict origin ingress to Cloudflare or the intended private path.

Stage 3: Configure Cloudflare Load Balancing Steering Policies

Create the load balancer for the hostname and attach ordered fallback pools. Configure steering to match the traffic-management objective, then review the applicable behavior in global traffic steering policies. Available steering policies and their outcomes depend on the selected configuration; verify the Cloudflare dashboard or API representation rather than inferring behavior from a policy name.

When choosing a steering policy, define the operational question it answers:

  • Geolocation-oriented steering can guide users toward designated pools, but does not by itself prove the chosen pool is fastest for every network path.
  • Dynamic steering uses Cloudflare measurements and configuration to influence selection, but observed client latency still includes DNS, connection, application, and origin behavior.
  • Random or weighted approaches can support controlled distribution when pools are intentionally equivalent, provided the weights reflect real capacity.
  • A fixed fallback order is appropriate when the service has a clear primary and standby relationship.

Configure fallback pools deliberately. Confirm the behavior expected when an origin becomes unhealthy, when an entire pool is unhealthy, and when all candidate pools are unavailable. Cloudflare’s Load Balancing concepts describe the relationship among load balancers, pools, monitors, and steering.

Geolocation steering and its DNS-only limits

A proxied Layer 7 load balancer's geo steering routes on the Cloudflare data center that received the request, closely tracking the requester's real location. A DNS-only load balancer instead infers location from the resolver making the DNS query, unless that resolver forwards an EDNS Client Subnet (ECS) hint and location_strategy prefers it (prefer_ecs: always|proximity|geo, mode: pop|resolver_ip as fallback). Large public resolvers don't universally forward ECS, so a DNS-only geo-steered hostname can silently steer users by resolver location, not client location. Test with resolvers Acme Shop's customers actually use before trusting a DNS-only geo result.

Dynamic steering needs a warm-up and a clean RTT signal

Dynamic (latency) steering picks the pool with the lowest round-trip time, an exponential weighted moving average built from the health monitor's own probe timings — the same origin health checks from Stage 1 double as the latency sensor. The Health Monitor Region must be "All Regions" or, on Enterprise, "All Data Centers," or the average is starved of samples. The first time dynamic steering is enabled for a pool, allow roughly ten minutes for Cloudflare to build an RTT profile; traffic follows the fallback order during that warm-up, so testing routing in the first few minutes and concluding it's broken is a common false alarm. A TCP monitor adds a caveat: if an origin terminates behind another provider's edge, the measured RTT reflects that hop, not the true application path.

Least Outstanding Requests for uneven request costs

Least Outstanding Requests steers new requests toward the pool handling the fewest in-flight requests, weighted by each pool's random-steering weight and health. It only works for proxied load balancers; Cloudflare cannot track in-flight counts for a DNS-only answer, so the policy quietly collapses to weighted-random there. Prefer it over geo or dynamic steering when a pool mixes cheap reads with expensive operations — report generation, bulk export — that can starve capacity before RTT or location alone would suggest a problem.

Ordered fallback pools and the acme-apac-secondary trial

Define the fallback pool order explicitly regardless of steering policy; it governs traffic during dynamic steering's warm-up and whenever every pool a policy would choose is unhealthy. Acme Shop's baseline stays default_pools: [acme-eu-primary, acme-us-standby] with acme-us-standby as fallback_pool. To trial geo steering into acme-apac-secondary without touching that baseline elsewhere, Acme Shop scopes the change with a region override:

{
  "load_balancer": {
    "hostname": "shop.acme-shop.example",
    "steering_policy": "geo",
    "default_pools": ["acme-eu-primary", "acme-us-standby"],
    "fallback_pool": "acme-us-standby",
    "region_pools": {
      "APAC": ["acme-apac-secondary", "acme-eu-primary"]
    }
  }
}

region_pools (and, at finer grain, country_pools and the Enterprise-only pop_pools) override default_pools only for the matched region; anything not listed falls back to default_pools. Verify the current API schema before relying on this shape in production.

Stage 4: Choose proxy mode before reasoning about cache or TTL

For Acme Shop's shop.acme-shop.example, use a proxied (orange-cloud) Layer 7 load balancer if the goal is request-level HTTP/S routing with Cloudflare WAF, Workers, and cache controls available. A cache HIT can be served at the edge without contacting an origin pool; a cache MISS proceeds through the current Layer 7 routing decision. Cache eligibility and cache key are separate Cache Rules/origin-header decisions, not a property supplied by Load Balancing. If Tiered Cache is active on the zone, Smart Tiered Cache picks one best upper-tier data center for the whole load-balanced pool, not one per origin — evaluate tiered-cache behavior at the pool level, not per origin.

DNS-only (gray-cloud) Load Balancing returns the selected endpoint address. If that endpoint is direct and non-proxied, the client connects to it directly, so the request cannot use Cloudflare cache, WAF, or Workers. If the selected endpoint is a proxied Cloudflare CNAME, the returned address is Cloudflare's and the subsequent HTTP request can still be proxied under that endpoint's proxy configuration. DNS TTL and resolver behavior affect when a new endpoint answer is requested, while existing connections can remain pinned to an earlier destination. Test the selected endpoint type explicitly; do not infer HTTP proxy behavior from the load balancer's DNS-only setting alone.

Set the load balancer TTL as a tradeoff between agility and DNS-query volume only for the DNS-only behavior it governs — Cloudflare enforces a floor near 30 seconds on Enterprise and 60 seconds otherwise — then verify the selected value against Cloudflare's current DNS record TTL guidance. Do not promise an exact failover time based only on the monitor interval or TTL.

Plan for these effects:

  • Recursive resolvers may retain an answer until its cached TTL expires; client and resolver behavior can introduce additional variation.
  • Users with existing persistent connections may not observe a changed DNS answer until the connection is retried or replaced.
  • Shorter TTLs can make new DNS answers available sooner, but do not eliminate monitoring detection time, resolver behavior, or origin-side recovery constraints.
  • DNS health-driven changes do not repair in-flight requests already sent to an impaired origin.

For proxied Layer 7 services, validate the selected affinity and endpoint-drain design where needed. For DNS-only services, do not assume short TTLs produce equivalent routing, cache, or session behavior.

Stage 5: Session Affinity and Load Balancer Failover Behavior

Session affinity and Cloudflare's automatic load balancer failover retry are different controls operators routinely conflate. Affinity decides which origin a client keeps talking to; the failover retry decides what happens to one request when that origin briefly fails. Both are proxied-only, for the same reason as WAF, cache, and Workers: Cloudflare cannot track a cookie or retry a connection it never terminates. A DNS-only hostname that needs sticky routing is really signaling that it should be proxied instead.

Proxied load balancers offer three affinity types: cookie-only (a __cflb cookie, secure and HttpOnly, defaulting to a 23-hour session unless a custom TTL is set), cookie with IP fallback (the same cookie, using client IP to pick an initial endpoint before a cookie exists), and header-based affinity (a session key derived from configured HTTP headers). Header-based affinity has a sharp edge case: if the header value changes mid-conversation — a client rotating an auth token or device ID — the session key changes with it, and the client can be silently re-bucketed to a different origin without any error.

Zero-downtime failover governs a single request that hits a Cloudflare-to-origin connection error (HTTP 521, 522, 523, 525, or 526): if another healthy origin exists in the same pool, Cloudflare retries it once before falling through to the pool's steering and fallback logic. The retry is deliberately narrow — one retry, one alternate origin, only for those connection-level codes — so it absorbs a single unlucky request while the monitor catches up; it is not a substitute for monitor-based detection. Set the failover mode (none, temporary, or sticky) to match the affinity in use: sticky failover updates the affinity cookie to the new origin, which is what most services want, but it is not supported for header-based affinity, so a service relying on header affinity should plan for temporary failover or none and treat that pairing as a known gap, not a bug to chase.

Stage 6: Test the Complete Failure Path Safely

Use a staging hostname and representative pools first. Test with a controlled amount of traffic and a rollback owner present. Never begin by disabling the only healthy production origin.

Run this test plan:

  1. Confirm each origin directly serves the expected application route and that its monitor endpoint returns the configured success response.
  2. Confirm the load-balanced hostname returns a DNS answer associated with the intended active pool and that real requests reach it.
  3. Introduce a reversible, monitor-visible failure to one origin. Verify the monitor marks it unhealthy according to its configured thresholds, then verify traffic selection avoids that origin where the configuration requires it.
  4. Restore the origin. Verify monitor recovery and the configured return behavior; do not assume that recovery necessarily moves traffic immediately or automatically without checking the chosen steering and fallback rules.
  5. Introduce a reversible failure affecting the active pool only after confirming the fallback pool has enough capacity. Observe both DNS answers and application outcomes across multiple resolver contexts or controlled clients.
  6. Load-test the receiving pool at the expected transferred traffic level, including critical reads, writes, authentication, and downstream calls.
  7. Test a partial degradation that returns 200 from the health endpoint while a critical route fails. Use the result to decide whether the monitor is intentionally narrow or insufficient for the service objective.
  8. If session affinity is enabled, confirm the affinity cookie or header survives a single zero-downtime retry unchanged, and repoints correctly after a full pool failover.
  9. If dynamic or geo steering is enabled, repeat the test both during the RTT warm-up and after it completes, and against resolvers that do and do not forward ECS.

Record timestamps for failure injection, monitor-state change, DNS observations, first client errors, fallback capacity signals, and recovery. This establishes an observed range for this architecture, not a universal failover commitment.

Representative pool-health API output; IDs shortened
{
"pool": "acme-eu-primary",
"health": "unhealthy",
"origins": [{
  "name": "acme-eu-web-1",
  "healthy": false,
  "failure_reason": "expected 200 from /healthz"
}],
"fallback_pool": "acme-us-standby"
}
Representative zero-downtime failover event; IDs shortened
{
"event": "zero_downtime_failover",
"pool": "acme-eu-primary",
"origin_failed": "acme-eu-web-1",
"origin_retry": "acme-eu-web-2",
"trigger_status": 523,
"session_affinity": "cookie",
"affinity_updated": false
}

Validation matrix

CheckExpected resultStop and investigate when
Positive: each pool direct testApplication route and /healthz return their documented resultsHealth endpoint is green while a required customer route fails
Positive: proxied Layer 7 hostnameRequests reach a healthy pool; WAF/Cache Rules behavior remains intactOrigin is exposed or edge controls unexpectedly disappear
Negative: DNS-only test hostname with a direct endpointResolver receives an endpoint address; no Cloudflare cache/WAF/Worker behavior is assumedTests mistake a DNS response for request-level failover or omit a separate proxied-CNAME endpoint test
Failure: reversible active-pool monitor failureMonitor marks it unhealthy and tested fallback capacity absorbs the controlled loadPool flaps, fallback saturates, or user journeys regress
Failure: single-origin zero-downtime retry vs. full pool failoverA single 52x error retries once and stays invisible to the user; a full pool failure moves traffic per the configured failover modeThe retry masks a real trend, or session affinity leaves clients pinned to a draining origin

Stage 7: Observe Health, Traffic, and Capacity

Watch three layers during rollout and incidents:

  • Cloudflare monitor and pool health: which origins and pools Cloudflare considers healthy, and the monitor failures that changed state.
  • DNS and traffic selection: query answers from representative resolvers, pool traffic distribution, and requests reaching each origin.
  • Application and infrastructure health: request success rate, latency, saturation, error budget impact, database capacity, queue depth, and dependency availability.

Cloudflare provides product-specific operational workflows in Load Balancing analytics. Pair those signals with origin telemetry; a green monitor plus a saturated origin is not a healthy service.

A pool failover is one line in a bigger timeline

Cloudflare's pool and monitor state answer "what does Cloudflare think is healthy," not "what did the customer experience." If Acme Shop fronts traffic through more than one provider, or runs load balancing across several properties from one desk, a Cloudflare pool failover needs to land on the same incident timeline as WAF, cache, and origin events elsewhere — the cross-provider correlation a supervision layer like Optimi's MYO exists to provide, so it doesn't read as unrelated noise.

Alert on actionable conditions such as an active pool losing capacity, a fallback pool receiving unexpected traffic, monitor flapping, origin errors rising after a steering change, and standby capacity dropping below the required transfer margin. Include the active configuration version or change reference in the operational timeline.

Rollback

Before changing a production pool, monitor, or steering policy, capture the current configuration and name the rollback action. Keep changes small enough that an observed regression has a clear cause.

Rollback choices depend on the change:

  • Restore the previous steering policy or fallback-pool order if a policy change sends traffic unexpectedly.
  • Re-enable a previously healthy origin only after confirming it can safely receive traffic.
  • Return a monitor to its prior endpoint or thresholds if a new check creates false unhealthy states, while investigating whether the old check masked a real service risk.
  • Shift traffic away from a pool only after confirming the destination capacity and dependency limits.
  • Revert the session affinity type or failover mode if a change leaves clients pinned to a draining origin or fragments sessions; confirm the cookie or header behavior after reverting, not only the dashboard setting.

After rollback, verify DNS observations, origin request distribution, monitor status, representative user flows, and receiving-pool saturation. Do not declare recovery solely because the Cloudflare configuration update succeeded.

Troubleshooting

SymptomLikely causeSafe diagnosticRecovery
Pool is unhealthy while direct app requests succeedMonitor path, body, TLS, timeout, or source access differsCompare the configured monitor contract to a non-mutating direct checkRestore the prior monitor only after documenting the discrepancy; correct the new monitor in staging
Users remain on impaired endpoint after DNS-only changeResolver cache or existing connection retained an old answerQuery representative resolvers and inspect connection reuseKeep service capacity for the TTL window; do not promise immediate client movement
Proxied hostname bypasses expected edge controlProxy status or hostname configuration is wrongConfirm orange-cloud proxy status and test WAF/Cache Rule tracesRestore proxied configuration and restrict direct origin ingress
Fallback pool receives traffic but saturatesStandby capacity or shared dependency was not sufficientCheck pool distribution, CPU, database, and queue limitsSteer only to a proven-capacity destination; scale or shed load before retrying
Health state flapsThresholds are too sensitive or dependency is intermittentCorrelate monitor transitions with origin telemetryRevert the recent threshold change and investigate the underlying dependency
Dynamic steering looks random or ignores latencyWarm-up not elapsed, monitor region narrower than All Regions, or a TCP monitor terminates behind a third-party edgeCheck each pool's RTT sample age and monitor regionWait out the warm-up, widen the monitor region, or switch to an HTTP/S monitor
Clients stay pinned to a draining origin despite a passing fallback poolSticky affinity, or failover mode set to none, kept the cookie pointed at the old originInspect the __cflb cookie's destination against current pool healthSet failover mode to temporary or sticky, and drain the origin explicitly instead of relying on the retry
DNS-only geo steering sends APAC users to the EU poolThe resolver did not forward ECS, so location fell back to resolver IPRepeat the DNS test against resolvers that do and do not forward ECSDocument the resolver-IP accuracy limit, or move the hostname to a proxied load balancer

Technical Caveats

Load Balancing behavior is shaped by the configured monitor, pool health, steering policy, fallback order, session affinity, failover mode, DNS TTL, resolver caching, client connections, and origin behavior. Consult current Cloudflare documentation before committing to a policy's availability, health detection, traffic movement, or recovery time. Define service objectives around measured user outcomes and tested capacity, not a vendor configuration value alone.

Authoritative references

Make Cloudflare load balancer failover part of a tested resilience plan

Talk to Optimi about origin health checks, steering tradeoffs, and failover testing for Cloudflare Load Balancing, evaluated alongside the Performance, Security, and Visibility of the rest of your edge.

Discuss traffic resilience