# Load Balancing

# Changelog



## 2025-04-15

**Introducing Support for Orange-Clouded Origin Resolution**

Newly created Cloudflare Load Balancers will resolve orange-clouded origin addresses, provided the origins belong to the same account and zone as the Load Balancer. Existing Load Balancers will continue using the current resolution method. If ownership validation fails, the new system falls back to the existing behavior and defaults to a gray-clouded (DNS-only) lookup, typically resolving to anycast addresses.

## 2025-03-13

**Update to Load Balancing analytics**

Load Balancing request rates in analytics may decrease for some customers as an improvement is made to our infrastructure. This decrease in Load Balancing analytics does not indicate a decrease in HTTP requests received.

## 2025-02-20

**Zone name added to Load Balancing API responses**

Load Balancing API responses for Load Balancers now include a `zone_name` property, which provides the name of the zone in the response data.

## 2025-02-10

**Fix for Cloudflare Tunnel Consistency**

Fixes to improve the consistency of Cloudflare Tunnel handling within Cloudflare Load Balancers. These changes ensure more reliable and predictable routing, particularly when tunnels are involved.

## 2025-01-24

**Update to Cloudflare Tunnel Steering**

Introduced changes to the resolution of proxied domains that are backed by Cloudflare Tunnels on the same zone. These changes correct how orange-clouded records are steered to Cloudflare Tunnels via Cloudflare Load Balancers.

## 2025-01-16

**Update to Pool Health Monitoring**

We made changes to how we resolve and monitor proxied origins to assess pool health. Our analysis indicates no impact to customer configurations or operations. Contact customer support if you notice any unexpected behavior.

## 2024-12-20

**Load Balancing with the China Network**

You can now enable load balancers to be deployed to the [China Network](/china-network/). Refer to the [documentation](/load-balancing/additional-options/load-balancing-china/) for more details.


# Cloudflare Load Balancing



Maximize application performance and availability

Cloudflare Load Balancing distributes traffic across your endpoints, which reduces endpoint strain and latency and improves the experience for end users.

***

## Features

**Load balancing and failover**

Distribute traffic evenly across your healthy endpoints, automatically failing over when an endpoint is unhealthy or unresponsive.

**Active monitoring**

Monitor your endpoints at configurable intervals and across multiple data centers to look for specific status codes, response text, and timeouts.

**Intelligent routing**

Choose whether to distribute requests based on endpoint latency, a visitor's geographic region, or even a visitor's GPS coordinates.

**Custom rules**

Customize the behavior of your load balancer based on the characteristics of individual requests.

**Analytics**

Review comprehensive analytics to evaluate traffic flow, assess endpoint health status, and review changes in pools and pool health over time.

***

## Related products

Actively monitor whether your origin server is online by sending specific requests at regular intervals.

Get enterprise-grade authoritative DNS service with the fastest response time, unparalleled redundancy, and advanced security with built-in DDoS mitigation and DNSSEC.

Route excess users to a custom-branded waiting room, helping preserve customer experience and protect origin servers from being overwhelmed with requests.

***

## More resources

[Plans](https://www.cloudflare.com/plans/#overview)
Compare available Cloudflare plans.

[Pricing](https://dash.cloudflare.com/?to=/:account/:zone/traffic/load-balancing/)
Explore pricing options for Load Balancing in the dashboard.

[Reference Architecture](/reference-architecture/architectures/load-balancing/)
Learn more about the structure of Cloudflare Load Balancers and their various configurations.

[Learning Paths](/learning-paths/)
Module-based guidance on Cloudflare product workflows.


# Additional DNS records

In addition to load balancing between DNS records used for IP resolution — `A`, `AAAA`, and `CNAME` records — Enterprise customers can also load balance between **MX** and **SRV** records.

## MX records

To load balance between multiple mail servers:

1. Make sure you have the [required DNS records](/dns/manage-dns-records/how-to/email-records/#send-and-receive-email) for your mail servers.
2. [Create a monitor](/load-balancing/monitors/create-monitor/) with a **Type** of *SMTP*.
3. [Create a pool](/load-balancing/pools/create-pool/) with your mail servers and attach the newly created monitor.
4. [Create a load balancer](/load-balancing/load-balancers/create-load-balancer/) that includes your newly created pools. Since it will forward SMTP traffic, the load balancer should be [unproxied (DNS-only)](/load-balancing/understand-basics/proxy-modes/#dns-only-load-balancing).

## SRV records

To load balance between different **SRV** records, which contain significantly more information than many other DNS records:

1. [Create your SRV records](/dns/manage-dns-records/how-to/create-dns-records/#create-dns-records).
2. [Create a monitor](/load-balancing/monitors/create-monitor/) with a **Type** of *UDP-ICMP* or *TCP*.
3. [Create a pool](/load-balancing/pools/create-pool/) with your various SRV records and attach the newly created monitor.
4. [Create a load balancer](/load-balancing/load-balancers/create-load-balancer/) that includes your newly created pools. This load balancer should be [unproxied (DNS-only)](/load-balancing/understand-basics/proxy-modes/#dns-only-load-balancing).

# Cloudflare Tunnel (published applications)

Cloudflare Tunnel (formerly Argo Tunnel) establishes a secure outbound connection which runs in your infrastructure to connect the applications and machines to Cloudflare.

For more details on how to use Load Balancing with Cloudflare Tunnel and public hostnames, refer to [Route tunnel traffic using a load balancer](/cloudflare-one/networks/connectors/cloudflare-tunnel/routing-to-tunnel/public-load-balancers/). For using private IPs instead, refer to [Set up private IPs with Tunnel](/load-balancing/private-network/warp-to-tunnel/).

# CNAME flattening for endpoints


When a [DNS-only (gray-clouded)](/load-balancing/understand-basics/proxy-modes/) load balancer selects an endpoint whose address is a hostname (for example `origin.example.com`), Cloudflare resolves that hostname to an IP address and returns an `A`/`AAAA` record to the client. This is _CNAME flattening_, and it matches how [CNAME flattening works in Cloudflare DNS](/dns/cname-flattening/).

Some use cases — such as third-party endpoints that perform their own DNS-based steering — require the load balancer to return the `CNAME` record itself instead of a resolved IP. The `flatten_cname` property on a pool endpoint lets you opt out of flattening on a per-endpoint basis.

:::note

This feature is only available with an Enterprise subscription.

:::

## When to use this

Turn `flatten_cname` off (`flatten_cname: false`) on an endpoint when:

- You want clients to receive a `CNAME` answer pointing at a third-party SaaS provider or cloud endpoint (for example `origin-b.example.com`).
- The endpoint resolves to addresses that are dynamic, geo-aware, or client-aware downstream.
- You are failing over between two hostname endpoints and want the client to resolve each provider's hostname directly.

Leave `flatten_cname` on (`flatten_cname: true`, the default) for normal IP-based or hostname endpoints where you just want a fast `A`/`AAAA` answer.

## Where it applies

`flatten_cname` only changes resolver output when all of the following are true:

| Condition                                                                  | Required value                                                                                                                                        |
| -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| Load balancer [proxy mode](/load-balancing/understand-basics/proxy-modes/) | DNS-only (gray-clouded). Proxied load balancers must return Cloudflare anycast IPs, so the setting is ignored.                                        |
| Endpoint address                                                           | A hostname (CNAME target). For raw IPv4/IPv6 endpoint addresses the setting has no effect.                                                            |
| Load balancer hostname                                                     | Not the zone apex. `CNAME` records at a zone apex are not permitted, so the load balancer falls back to flattening at the apex.                       |
| The selected endpoint                                                      | Steering selected this specific endpoint. Setting `flatten_cname: false` on endpoint A has no effect when steering picks endpoint B in the same pool. |

If the selected endpoint has `flatten_cname: false` but any of the conditions in the preceding table is not met, the load balancer flattens the CNAME and returns `A`/`AAAA` records as if the toggle were on.

## Configure CNAME flattening

`flatten_cname` is configured per endpoint inside a pool, alongside `name`, `address`, `weight`, and other endpoint fields. You can set it in the Cloudflare dashboard, the API, or Terraform.

 

### Dashboard

In the dashboard, this setting appears as a **Flatten CNAME** toggle on each endpoint in a pool. Turn the toggle off to return the endpoint hostname as a `CNAME` record.

1. In the Cloudflare dashboard, go to the **Load Balancing** page.

   

https://dash.cloudflare.com/?to=/:account/load-balancing

2. Select the **Pools** tab.
3. On the pool that contains the endpoint, select **Edit**.
4. In the **Endpoints** section, find the endpoint you want to change.
5. Turn **Flatten CNAME** off.
6. Select **Save**.

**Flatten CNAME** is only available for endpoints whose address is a hostname. Endpoints that use an IP address cannot turn it off.

 

### API

Use [Create Pool](/api/resources/load_balancers/subresources/pools/methods/create/) or [Edit Pool](/api/resources/load_balancers/subresources/pools/methods/edit/) and set `flatten_cname` on each endpoint in the `origins` array.

`POST /accounts/{account_id}/load_balancers/pools`

`flatten_cname` defaults to `true` when omitted, preserving today's behavior for existing pools and endpoints.

 

### Terraform

Set the attribute on each endpoint inside a `cloudflare_load_balancer_pool` resource.

```hcl
resource "cloudflare_load_balancer_pool" "primary" {
  account_id = var.account_id
  name       = "primary-pool"

  origins = [
    {
      name          = "origin-a"
      address       = "origin-a.example.com"
      enabled       = true
      weight        = 1
      flatten_cname = false
    },
    {
      name          = "origin-b"
      address       = "origin-b.example.com"
      enabled       = true
      weight        = 1
      flatten_cname = false
    },
    {
      name    = "fallback-ip"
      address = "203.0.113.10"
      enabled = true
      weight  = 1
    }
  ]
}
```

 

## Verify

Query the load balancer hostname with `dig`:

```sh
dig lb.example.com A +short
```

- If steering selected an endpoint where `flatten_cname` is `false`, the answer section contains a `CNAME` record pointing at the endpoint address (for example, `origin-a.example.com.`). The client (or its resolver) is responsible for resolving that `CNAME` further.
- If steering selected an endpoint where `flatten_cname` is `true` (or an endpoint whose address is an IP), the answer contains the resolved `A`/`AAAA` records.

Because the answer depends on which endpoint steering selects, repeated `dig` queries against the same load balancer can legitimately alternate between `CNAME` and `A`/`AAAA` answers when a pool mixes hostname endpoints with `flatten_cname: false` and IP endpoints.

## Health monitors

Endpoint health monitors are unaffected by this setting. Cloudflare always resolves the endpoint hostname to an IP and probes the underlying service using an uncached DNS lookup. Turning off flattening only changes what is returned to the client at DNS query time — health status continues to reflect the real backend reachability.

## Analytics

Per-endpoint request counts and steering decisions remain visible in [load balancing analytics](/load-balancing/reference/load-balancing-analytics/), keyed by endpoint name. This lets you track how traffic is distributed across `CNAME`-returning endpoints.

## Limitations

- Proxied (orange-clouded) load balancers: `flatten_cname` is ignored. Proxied load balancers must resolve to Cloudflare anycast IPs to deliver Cloudflare's HTTP/HTTPS proxy features.
- Zone apex load balancers: `flatten_cname` is ignored because `CNAME` records are not permitted at a zone apex.
- IP endpoints: `flatten_cname` has no effect — there is no `CNAME` to flatten or return.
- DNS resolver caching: As with any DNS-only load balancer, downstream resolvers may cache the returned record for the TTL. Clients that ignore TTLs may continue to use a previously cached `CNAME` or `A` answer.
- Plan requirement: Available to Enterprise customers on the Load Balancing add-on.

## Related

- [DNS CNAME flattening](/dns/cname-flattening/) — the equivalent feature for non-load-balancer DNS records.
- [Proxy modes](/load-balancing/understand-basics/proxy-modes/) — when to use DNS-only versus proxied load balancing.
- [Common configurations](/load-balancing/load-balancers/common-configurations/) — patterns including active-active failover that benefit from CNAME-returning endpoints.


# DNS persistence

This guide explains how to achieve DNS persistence when using Cloudflare Load Balancing, similar to functionality provided by traditional DNS-based load balancers.

DNS persistence ensures that subsequent DNS requests from the same local DNS server receive the same IP address. This is useful for applications that require session consistency, such as VPN connections or authentication systems.

Cloudflare Load Balancing can achieve DNS persistence using different configuration approaches for DNS-only load balancing.

---

## DNS-only load balancing persistence

For DNS-only load balancing, Cloudflare offers three methods to achieve DNS persistence:

### Method 1: Geo-steering based on PoP location (Recommended)

This method uses geographic steering based on the Cloudflare Point of Presence (PoP) that receives the DNS request.

#### Configuration steps

1. Create a pool for each endpoint. Do not apply load shedding to either pool.
2. Create a DNS-only load balancer and add both pools. Ensure `pool_1` is ordered before `pool_2`.
3. Under **Traffic Steering**, select **Geo Steering**.
4. Create a geo-steering rule for a region (for example, **Eastern North America**) and select the same pools but in reverse order (`pool_2` first, then `pool_1`).
5. Use **Never prefer ECS** and **PoP location** to determine the source of the request.

#### How it works

All requests received at Cloudflare PoPs in the specified region are sent to one endpoint, while requests from other regions are sent to the other endpoint.

#### Why this is recommended

Using the Cloudflare PoP that received the request as criteria for steering is more stable than IP hashing or splitting IP space, as it is not affected by recursive DNS providers using different egress IPs.

### Method 2: Load shedding with IP hash

This method uses load shedding to distribute traffic based on the source IP address of the recursive DNS resolver.

#### Configuration steps

1. Create a pool for each endpoint (for example, `pool_1` with `endpoint_1` and `pool_2` with `endpoint_2`).
2. On the first pool, select **Hash** under **Endpoint Steering**.
3. Configure **Load Shedding**:
   - **Policy**: IP Hash
   - **Shed %**: 50% (to split traffic evenly between two pools)
4. Create a DNS-only load balancer and add both pools. Ensure `pool_1` is ordered before `pool_2`.
5. Do not configure additional traffic steering or rules.

#### How it works

This configuration sheds half of the requests to the second pool using an IP hash and respects session affinity per source IP of the recursive resolver.

#### Limitations

Some recursive DNS providers (like Google DNS 8.8.8.8 or Quad9 9.9.9.9) may use different egress IPs randomly, which can reduce persistence stability.

### Method 3: Custom rules with IP source filtering

This method uses custom rules to split traffic based on IP address ranges.

#### Configuration steps

1. Create a pool for each endpoint. Do not apply load shedding to either pool.
2. Create a DNS-only load balancer and add both pools. Ensure `pool_1` is ordered before `pool_2`.
3. Do not configure traffic steering.
4. Create a **Custom Rule** with:
   - **Field**: IP Source Address
   - **Operator**: is in
   - **Value**: A subset of IP space (for example, `0.0.0.0/1` for the lower half of IPv4 space)
5. For the rule action, choose **Override** > **Endpoints** and set the pools in reverse order (`pool_2`, `pool_1`).

#### How it works

Traffic with source IPs in the lower half of IPv4 space is sent to one endpoint, while traffic in the upper half is sent to the other endpoint.

#### Limitations

Similar to Method 2, this approach may be less stable with recursive DNS providers that use varying egress IPs.

---

## Related resources

- [Session Affinity](/load-balancing/understand-basics/session-affinity/)
- [Load Shedding](/load-balancing/additional-options/load-shedding/)
- [Geo Steering](/load-balancing/understand-basics/traffic-steering/steering-policies/geo-steering/)
- [Custom Rules](/load-balancing/additional-options/load-balancing-rules/)

# Additional configuration

Beyond [creating a simple load balancer](/load-balancing/load-balancers/create-load-balancer/), you may want to further customize how your load balancer routes traffic or integrate your load balancer with other Cloudflare products.

## Customize load balancer behavior

- Route traffic according to characteristics of each request by [creating custom rules](/load-balancing/additional-options/load-balancing-rules/)
- Protect at-risk endpoints from reaching failover by [setting up load shedding](/load-balancing/additional-options/load-shedding/)
- Take endpoints out of rotation for [planned maintenance](/load-balancing/additional-options/planned-maintenance/)
- Return endpoint hostnames as `CNAME` records to support downstream DNS steering with [CNAME flattening for endpoints](/load-balancing/additional-options/cname-flattening/)

## Integrate with other Cloudflare products

- Bring load balancing to your TCP or UDP applications with [Cloudflare Spectrum](/load-balancing/additional-options/spectrum/)
- Further secure endpoint access with [Cloudflare Tunnel](/load-balancing/additional-options/cloudflare-tunnel/)

## Integrate with 3rd parties

- Increase visibility by [sending health monitor notifications to PagerDuty](/load-balancing/additional-options/pagerduty-integration/)

# Load Balancing with the China Network

To enable load balancers to be deployed to the [China Network](/china-network/), your zone will need to meet the following two criteria:

1. A valid [ICP license](/china-network/concepts/icp/) for the zone in question.
2. The zone must be provisioned with access to the China Network.

Once these two criteria are met, any newly created load balancer will be automatically deployed to the China Network. When choosing a region for a pool's health checks, `China` is now available to be selected in both the dashboard and API.

You can also create a load balancer by sending a `POST` request to the following endpoint. To deploy to the China Network with the API, the `networks` array in the API call must contain `jdcloud` as a value in addition to `cloudflare`. Refer to the [Cloudflare API documentation](/api/resources/load_balancers/methods/create/) for details on the required fields and their formats.

```bash
https://api.cloudflare.com/client/v4/zones/{zone_id}/load_balancers
```

## Limitations

Load balancers deployed to the China Network currently have the following limitations:

- Only cookie-based session affinity is supported.
- Private network off-ramps (Tunnel, GRE, IPsec) are not supported.
- Private Network Load Balancing is not available on the China Network.

# Load shedding


Use load shedding to prevent an at-risk endpoint from [becoming unhealthy](/load-balancing/understand-basics/health-details/) and starting the failover process.

Once you configure load shedding on a pool, that pool will begin diverting traffic to other pools according to your load shedding settings and the load balancer's [steering policy](/load-balancing/understand-basics/traffic-steering/steering-policies/).

## Step 1 — Identify at-risk endpoints

Using your internal metrics, identify endpoints at risk of reaching their failure threshold.

- If your endpoint is seeing increased traffic but is not yet at risk of failure, start with [Step 2](#step-2--shed-default-traffic-from-a-pool).
- If your endpoint is about to fail, start with [Step 4](#step-4--shed-additional-traffic-optional).

## Step 2 — Shed default traffic from a pool

Once you have identified an at-risk endpoint, shed a small amount of **Default** traffic from that endpoint's pool. This traffic is not affiliated with existing [Session affinity](/load-balancing/understand-basics/session-affinity/) sessions.

Configure load shedding via the [dashboard](#configure-via-dashboard) or the [API](#configure-via-api).

### Configure via dashboard

To enable load shedding for a specific pool via the dashboard:

1. Go to **Load Balancing**.
2. Select the **Pools** tab.
3. On a pool, select **Edit**.
4. Open the **Configure Load Shedding** dropdown.
5. For **Default traffic**, select a **Policy** and a **Shed %**:

**Policy options**

When shedding **Default traffic**, you have two **Policy** options:

- **Random**: Randomly sheds the percentage of requests specified in the _Shed %_. Distributes traffic more accurately, but may cause requests from the same IP to hit different endpoints.
- **IP hash**: Sheds the percentage of IP address hash space specified in the _Shed %_. Ensures requests from the same IP will hit the same endpoint, but may shed a significantly higher or lower percentage of requests.

For more guidance on choosing a policy, refer to [Shedding policies](#shedding-policies).

**Shed %**

When choosing a **Shed %**, start with a small percentage and increase gradually. Particularly if you choose the [IP hash shedding policy](#shedding-policies), you might shed more traffic than expected.

### Configure via API

To enable load shedding for a specific pool via the API, [update the values](/api/resources/load_balancers/subresources/pools/methods/update/) for the pool's `load_shedding` object.

**Example request**


```bash title="Request"
curl --request PATCH \
"https://api.cloudflare.com/client/v4/accounts/{account_id}/load_balancers/pools/{pool_id}" \
--header "Authorization: Bearer <API_TOKEN>" \
--header "Content-Type: application/json" \
--data-binary '{
  "load_shedding": {
    "default_percent": 20,
    "default_policy": "random",
    "session_percent": 0,
    "session_policy": "hash"
  }
}'
```


For more guidance on choosing a shedding policy, see [Shedding policies](#shedding-policies).

## Step 3 — Monitor traffic

Once you have started shedding default traffic, evaluate the effects by reviewing the [**Overview** metrics](/load-balancing/reference/load-balancing-analytics/) in Load Balancing analytics. Based on these numbers and your internal metrics, you will know whether you need to divert additional traffic from the pool.

If you see increased traffic to a pool, you may need to shed additional traffic. Pools shed a percentage of total traffic, so any increase in total traffic will also increase the traffic reaching your pool.

## Step 4 — Shed additional traffic (optional)

If you need to shed additional pool traffic:

1. Follow the steps outlined in [Step 2](#step-2--shed-default-traffic-from-a-pool).
   - In the dashboard, increase the **Shed %** for **Default traffic** and/or **Session affinity traffic**.
   - For the API, increase the value for `default_percent` and/or `session_percent`.

Since shedding **Session Affinity traffic** will disrupt [existing sessions](/load-balancing/understand-basics/session-affinity/) and may degrade the customer experience, only enable this option if your pool is in imminent danger of becoming unhealthy or your pool has a high percentage of traffic related to existing sessions. For more guidance, see [Shedding policies](#shedding-policies).

## Step 5 — Disable load shedding

Once an endpoint is no longer at risk, remove load shedding from the pool.

To remove load shedding in the dashboard, perform the same steps as [Configure load shedding via the dashboard](#configure-via-dashboard) but set the **Shed %** to `0` for both **Default traffic** and **Session affinity traffic**.

To remove load shedding via the API, perform the same steps as [Configure load shedding via the API](#configure-via-api) but set the `load_shedding` object to `null`.

## Additional notes

### Shedding policies

For **Default traffic**, you have two choices for shedding policy.

A _Random_ policy:

- Randomly sheds the percentage of requests specified in the _Shed %_.
- Distributes traffic more accurately because it sheds at the request level.
- May cause requests from the same IP to hit different endpoints, potentially leading to cache misses, inconsistent latency, or session disruption for [DNS-only load balancers](/load-balancing/understand-basics/proxy-modes/#dns-only-load-balancing).

An _IP hash_ policy:

- Sheds the percentage of IP address hash space specified in the _Shed %_.
- Ensures requests from the same IP will hit the same endpoint, which will increase cache hits, provide consistent latency, and preserve sessions.
- Can over- or under-shed requests, since hashing does not guarantee a perfectly even IP distribution and individual IPs may be responsible for different percentages of your requests.

Choose a _Random_ policy when you want a more accurate distribution of raw requests and an _IP hash_ policy when you want to prevent a single IP from flapping between different endpoints.

For **Session Affinity traffic**, you can only use an _IP hash_ policy since these requests relate to existing sessions. Only increase the _Shed %_ if you are comfortable disrupting [existing sessions](/load-balancing/understand-basics/session-affinity/).

### Fallback pools

If all pools within a load balancer have _Load shedding_ enabled, some traffic will go to the fallback pool. To prevent any traffic from reaching the fallback pool, ensure at least one pool within the load balancer **does not** have load shedding enabled.

### Pools in multiple load balancers

If you enable load shedding on a pool, it will shed the same percentage of traffic across all your load balancers. If you need an endpoint to shed different percentages of traffic for different load balancers, put that endpoint in multiple pools.


# Override HTTP Host headers

When your application needs specialized routing (`CNAME` setup or custom hosts like Heroku), you can customize the `Host` header used in health monitors on a per-endpoint or per-monitor level.

:::caution[Important]

If you set a header override on an individual endpoint, it will take precedence over a header override set on a monitor.

Also, if you configure an [Origin Rule](/rules/origin-rules/) that overrides the hostname and set up a header override in your Load Balancer configuration, the Load Balancer configuration will take precedence over the Origin Rule hostname override.

:::

## Per endpoint Host header override

To balance traffic across multiple hosts, add `Host` headers to individual endpoints within the same pool.

For example, you might have a pool with endpoints hosted in multiple AppEngine projects or Amazon S3 buckets. You also might want to set up specific failover endpoints within a pool.

Since these examples require specific hostnames per endpoint, your load balancer will not properly route traffic *without* a `Host` header override.

If you need an endpoint `Host` header override, add it when [creating](/load-balancing/pools/create-pool/) or editing a pool. For security reasons, this header must meet one of the following criteria:

* Is a subdomain of a zone associated with this account
* Matches the endpoint address
* Publicly resolves to the endpoint address

## Host header prioritization

If you set a header override on an individual endpoint, it will take precedence over a header override set on a monitor during health monitor requests.

For example, you might have a load balancer for `www.example.com` with the following setup:

* Pools:

  * Pool 1:

    * Endpoint 1 (`Host` header set to `lb-app-a.example.com`)
    * Endpoint 2

  * Pool 2:

    * Endpoint 3
    * Endpoint 4 (`Host` header set to `lb-app-b.example.com`)

* Monitor (`Host` header set to `www.example.com`)

In this scenario, health monitor requests for **Endpoint 1** would use `lb-app-a.example.com`, health monitor requests for **Endpoint 4** would use `lb-app-b.example.com`, and all other health monitor requests would default to `www.example.com`. For more information on updating your custom host configuration to be compatible with Cloudflare, see [Configure Cloudflare and Heroku over HTTPS](/support/third-party-software/others/configure-cloudflare-and-heroku-over-https/).

For a list of endpoints that override a monitor's `Host` header:

1. On a monitor, select **Edit**.
2. Select **Advanced health monitor settings**.
3. If you have endpoint overrides, you will see **Endpoint host header overrides**.

![Example configuration of endpoint host header overrides](~/assets/images/load-balancing/origin-host-header-override.png)


# Integrate with PagerDuty

To integrate Cloudflare health monitor notifications with PagerDuty, follow the steps outlined in PagerDuty’s [Email Integration Guide](https://www.pagerduty.com/docs/guides/email-integration-guide/). If you do not have a PagerDuty account, you will first need to set that up.

PagerDuty will generate an email address that will create incidents based on emails sent to that address. For help locating that email address, refer to the [PagerDuty documentation](https://www.pagerduty.com/docs/guides/email-integration-guide/).

When creating the Notifier object, configure the email to go to the PagerDuty integration email. Consequently, whenever a pool or endpoint goes down, an Incident will be created to capture it.

# Perform planned maintenance

When you change application settings or add new assets, you will likely want to make these changes on one endpoint at a time. Going endpoint by endpoint reduces the risk of changes and ensures a more consistent user experience.

To take endpoints out of rotation gradually (important for session-based load balancing), [enable endpoint drain](#gradual-rotation) on your load balancer. This option is only available for [proxied load balancers (orange-clouded)](/load-balancing/understand-basics/proxy-modes/).

To direct traffic away from your endpoint immediately, [adjust settings on the pool or monitor](#immediate-rotation).

:::note

If you want to divert traffic from an endpoint to prevent it from becoming unhealthy, use [Load Shedding](/load-balancing/additional-options/load-shedding/) instead.

:::

:::caution[Existing connections are not terminated]
When an endpoint becomes unhealthy, Cloudflare Load Balancing stops routing **new** requests to it. However, existing connections (including long-lived WebSocket connections) are **not** terminated — they remain open until they close naturally.

If you need graceful connection draining, use [endpoint drain](#gradual-rotation) to proactively take endpoints out of rotation before maintenance, rather than relying on health check failures alone.
:::

## Before you begin

Before disabling any endpoint, review the settings for any affected load balancers and pools.

If a pool falls below its **Health Threshold**, it will be considered **Unhealthy** and — depending on the load balancer setup and steering policy — a load balancer may begin routing traffic away from that pool.

## Gradual rotation

:::note

Endpoint drain is only available for [proxied load balancers (orange-clouded)](/load-balancing/understand-basics/proxy-modes/).

:::

With [session-based load balancing](/load-balancing/understand-basics/session-affinity/), it is important to direct all requests from a particular end user to a specific endpoint. Otherwise, information about the user session — such as items in their shopping cart — may be lost and lead to negative business outcomes.

To remove an endpoint from rotation while still preserving session continuity, set up **Endpoint drain** on a load balancer:

1. On a new or existing load balancer, go to the **Hostname** step.
2. Make sure you have enabled **Session Affinity**.
3. For **Endpoint drain duration**, enter a time in seconds. If this value is less than the **Session TTL** value, you will affect existing sessions.
   ![Example configuration of session affinity with endpoint drain](~/assets/images/load-balancing/session-affinity-3.png)
4. Save your changes to the load balancer.
5. Click **Manage Pools**.
6. Disable an endpoint. Your load balancer will gradually drain sessions from that endpoint.
7. On your load balancer, expand your pools to find the disabled endpoint. You will see the estimated **Drain Time** counting down.
   ![Example showing load balancer draining in progress](~/assets/images/load-balancing/session-affinity-4.png)
8. When a drain is **Complete**, there are no longer any connections to that endpoint.
   ![Example showing load balancer draining complete](~/assets/images/load-balancing/session-affinity-5.png)
9. Perform your required maintenance or upgrades.
10. To bring your endpoint back online, re-enable the endpoint.

## Immediate rotation

To direct traffic away from an endpoint immediately:

1. Do one of the following actions:
   * On the endpoint's [monitor](/load-balancing/monitors/), update the monitor settings so the endpoint will fail health monitor requests, such as putting an incorrect value for the **Response Body** or **Response Code**.
   * On the pool, disable the endpoint.
   * On the pool, set the [endpoint weight](/load-balancing/understand-basics/traffic-steering/origin-level-steering/#weights) to `0` (though traffic may still reach the endpoint if it is included in multiple pools).
2. Monitor [Load Balancing Analytics](/load-balancing/reference/load-balancing-analytics/) to make sure no requests are reaching the pool.
   * If you are using [DNS-only load balancing (gray-clouded)](/load-balancing/understand-basics/proxy-modes/), changes may be delayed due to DNS resolver caching.
3. Perform your required maintenance or upgrades.
4. Undo the changes you made in **Step 1**.


# Spectrum


You can configure [Spectrum](/spectrum/) with Load Balancing to bring resiliency to your TCP or UDP based applications.

Leverage health monitors, failover, and traffic steering by selecting a load balancer as **Origin** when creating your Spectrum application.

The exact settings will vary depending on your use case. Refer to the following steps to understand the workflow.

---

## Set up

### 1. Configure your load balancer

1. In the Cloudflare dashboard, go to the **Load Balancing** page.

   

https://dash.cloudflare.com/?to=/:account/load-balancing

2. Select an account where the Load Balancing add-on is [enabled](/load-balancing/get-started/enable-load-balancing/).

3. Go to **Load Balancing** and select **Create load balancer**.

4. On the **Load Balancer Setup**, select **Public load balancer**

5. Choose the website to which you want to add this load balancer.

6. On the **Hostname** page, define the settings presented and select **Next**.
   - Enter a **Hostname**, which is the DNS name at which the load balancer is available. For more details on record priority, refer to [DNS records for load balancing](/load-balancing/load-balancers/dns-records/).
     :::caution

     To prevent issues with DNS resolution, the load balancer hostname should be different from the hostname (or domain) you intend to define for your Spectrum application.
     :::

   - Keep the orange cloud icon enabled, meaning the load balancer is proxied. This refers to the [proxy mode](/load-balancing/understand-basics/proxy-modes/) and, with Spectrum, traffic is always proxied.
   - Keep **Session Affinity** and **Failover across pools** disabled as these features are not supported with Spectrum.

7. On the **Add a Pool** page, define the settings presented and select **Next**.
   - Select one or more existing pools or [create a new pool](/load-balancing/pools/create-pool/#create-a-pool) [^1].
   - If needed, update the [fallback pool](/load-balancing/understand-basics/health-details/#fallback-pools) [^2].

8. On the **Monitors** page, define the settings presented and select **Next**.
   - Review the monitors attached to your pools.
   - If needed, you can attach an existing monitor or [create a new monitor](/load-balancing/monitors/create-monitor/#create-a-monitor).
   :::caution[IP Access Rules and health checks]
   If your Spectrum application is used as a Load Balancer endpoint and has [IP Access Rules](/spectrum/reference/configuration-options/#ip-access-rules) enabled, Cloudflare's health check probes must be allowed by your rules. Otherwise, health checks will be blocked and all endpoints will be marked as unhealthy. To resolve this, add [Cloudflare IP addresses](https://www.cloudflare.com/ips/) to your IP Access Rules allowlist. Refer to [Spectrum Troubleshooting](/spectrum/reference/troubleshooting/#health-checks-fail-when-ip-access-rules-are-enabled) for details.
   This does not apply when the Spectrum application's origin is a Load Balancer hostname. In that architecture, the monitor probes the origin directly and is not affected by IP Access Rules on the Spectrum app.
   :::

9. On the **Traffic Steering** page, choose an option for [Traffic steering](/load-balancing/understand-basics/traffic-steering/steering-policies/) and select **Next**.

10. Keep **Custom Rules** page empty as this feature is not supported with Spectrum.

11. On the **Review** page:

- Review your configuration and make any changes.
  - If you set traffic steering to **Off**, re-order the pools in your load balancer to adjust the fallback order.
  - If you chose to set traffic steering to Random, you can [set weights to your pools](/load-balancing/understand-basics/traffic-steering/steering-policies/standard-options/#random-steering) (via the [API](/api/resources/load_balancers/methods/create/)) to determine the percentage of traffic sent to each pool.
- Choose whether to **Save as Draft** or **Save and Deploy**.

### 2. Configure your Spectrum application

---

## Limitations

[^1]: Within Cloudflare, pools represent your endpoints and how they are organized. As such, a pool can be a group of several endpoints, or you could also have only one endpoint (an origin server, for example) per pool.

[^2]: A fallback pool is the pool of last resort. When all pools are disabled or unhealthy, this is where the load balancer will send traffic.


# Actions

Add **actions** to customize how your load balancer responds to certain HTTP requests.

Each load balancing rule includes one or more actions.

## Supported Actions

This table lists the actions available for Load Balancing rules. For a walkthrough, refer to [Create Load Balancing rules](/load-balancing/additional-options/load-balancing-rules/create-rules/).

<table style='width:100%'>
  <thead>
    <tr>
      <th style='width:20%'>Action</th>
      <th style='width:20%'>Options</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><em>Fixed response</em></td>
      <td><em>N/A</em></td>
      <td>Respond to the request with an HTTP status code and an optional message.</td>
    </tr>
    <tr>
      <td><em>Override</em></td>
      <td><em>Session affinity</em></td>
      <td>Set the <a href="/load-balancing/understand-basics/session-affinity/">session affinity</a> for the request. You can customize cookie behavior and session time-to-live (TTL).</td>
    </tr>
    <tr>
      <td><em>Override</em></td>
      <td><em>Load balancer TTL</em></td>
      <td>Customize the load balancer session time-to-live (TTL).</td>
    </tr>
    <tr>
      <td><em>Override</em></td>
      <td><em>Steering policy</em></td>
      <td>Update the <a href="/load-balancing/understand-basics/traffic-steering/steering-policies/">steering policy</a> associated with your load balancer.</td>
    </tr>
    <tr>
      <td><em>Override</em></td>
      <td><em>Fallback pool</em></td>
      <td>Update the <a href="/load-balancing/understand-basics/traffic-steering/steering-policies/standard-options/#off---failover">fallback pools</a> associated with your load balancer.</td>
    </tr>
    <tr>
      <td><em>Override</em></td>
      <td><em>Pools</em></td>
      <td>Update the <a href="/load-balancing/pools/">pools</a> associated with your load balancer.</td>
    </tr>
    <tr>
      <td><em>Override</em></td>
      <td><em>Region pools</em></td>
      <td>Update the <a href="/load-balancing/understand-basics/traffic-steering/steering-policies/geo-steering/">region pools</a> associated with your load balancer.</td>
    </tr>
    <tr>
      <td><em>Override</em></td>
      <td><em>Country pools</em></td>
      <td>Update the <a href="/load-balancing/understand-basics/traffic-steering/steering-policies/geo-steering/">country pools</a> associated with your load balancer.</td>
    </tr>
    <tr>
      <td><em>Override</em></td>
      <td><em>Terminates</em></td>
      <td>Stop processing Load Balancing rules and apply the current load balancing logic to the request.</td>
    </tr>

  </tbody>
</table>

# Create custom rules

Create and manage [Load Balancing rules](/load-balancing/additional-options/load-balancing-rules/) in the **Custom Rules** page, which is part of the Create/Edit Load Balancer workflow found in **Traffic** in the dashboard.

***

## Prerequisites

* **Understand whether Cloudflare proxies your traffic**: Depending on the [proxy status](/load-balancing/understand-basics/proxy-modes/) of your traffic, you may have access to different fields for your load balancing rules. For more details, refer to [Supported fields and expressions](/load-balancing/additional-options/load-balancing-rules/reference/).

***

## Example Workflow

1. In the Cloudflare dashboard, go to the **Load Balancing** page.

   

https://dash.cloudflare.com/?to=/:account/load-balancing

2. Edit an existing load balancer or [create a new load balancer](/load-balancing/load-balancers/create-load-balancer/).
3. From the Load Balancer workflow, select **Custom Rules**.
4. Select **Create Custom Rule**.
5. In the **Field** drop-down list, choose an HTTP property. For more details, refer to [Supported fields](/load-balancing/additional-options/load-balancing-rules/reference/).
6. In the **Operator** drop-down list, choose an operator. For more details, refer to [Operators](/load-balancing/additional-options/load-balancing-rules/reference/#operators-and-grouping-symbols).
7. Enter the value to match. When the field is an ordered list, **Value** is a drop-down list. Otherwise, **Value** is a text input.
8. (Optional) To create a compound expression using logical operators, select **And** or **Or**.
9. For an action, choose **Respond with fixed response** or **Override** and enter additional details. For a full list of actions, refer to [Actions](/load-balancing/additional-options/load-balancing-rules/actions/).
10. (Optional) Select **Add another override**.
11. After you create your rule, select **Save and Deploy** or **Save as Draft**.
12. Select **Next** and review your changes.
13. Select **Save** to confirm.

:::caution[Warning]

To save a new load balancer rule, make sure to save both the rule **and** the overall load balancer configuration.

:::

:::note

In general, for non-terminating actions, the last change made by rules within the same [phase](/ruleset-engine/about/phases/) will win (later rules can overwrite changes made by previous ones). However, for [terminating actions](/ruleset-engine/rules-language/actions/), such as Block, Redirect, or any of the challenge actions, rule evaluation will stop and the action is executed immediately.

Load Balancer Custom Rules override the default Load Balancer settings, including pool and origin selection. These are non-terminating actions, so the last rule applied will override any prior rules.

:::

## Example use case

### URL-based routing

If you want to host `example.com/blog` separately from your main website, for example, use the following custom rule.

<strong>When incoming requests match</strong>:

| Field    | Operator | Value   |
| -------- | -------- | ------- |
| URI Path | contains | `/blog` |

<strong>Then</strong>:

| Action    | Options | Value           |
| --------- | ------- | --------------- |
| Overrides | Pools   | `<BLOG_SERVER>` |


# Expressions

[Load Balancing rules](/load-balancing/additional-options/load-balancing-rules/) use two kinds of expressions:

* [Simple expressions](#simple-expressions) compare a value from an HTTP request to a value defined in the expression. A simple expression is identified by the presence of a **comparison operator** (*equals* or *less than*, for example).

* [Compound expressions](#compound-expressions) combine two or more simple expressions into a single expression. Compound expression contains a **logical operator** (*and*, *or*, for example). With compound expressions you can tailor rules to specific use cases with a high degree of accuracy and precision.

***

## Simple expressions

Simple expressions are composed of three elements:

1. A **field** that represents a property of an HTTP request.
2. A representative **value** for that field which Cloudflare compares to the actual request value.
3. A **comparison operator**, which specifies how the value defined in the expression must relate to the actual value from the request for the operator to return `true`.

When the comparison operator returns `true`, the request matches the expression.

This example expression returns true when a request URI path contains `/content`:

```sql
(http.request.uri.path contains "/content")
```

In general, simple expressions use this pattern:

```sql
<field> <operator> <value>
```

For more details, refer to [Supported fields and operators](/load-balancing/additional-options/load-balancing-rules/reference/).

***

## Compound expressions

A compound expression uses a **logical operator** (*and*, *or*, for example) to combine two or more expressions. Compound expressions allow you to build complex statements within a single expression.

The example expression below returns true when both the HTTP request URI path contains `/content` and the query string contains `webserver`:

```sql
(http.request.uri.path contains "/content")
and (http.request.uri.query contains "webserver")
```

In general, compound expressions use this pattern:

```sql
<expression> <logical operator> <expression>
```

A compound expression can be an operand of a logical operator. This allows multiple operators to construct a compound expression from many individual expressions.

For more details, refer to [Supported fields and operators](/load-balancing/additional-options/load-balancing-rules/reference/).

***

## Working with expressions

The Expression Builder’s visual interface allows you to build expressions without worrying about field names and syntax.

By comparison, the Expression Editor is text only, but it supports advanced features not available in the builder.

### Expression Builder

Compound expressions are easier to scan when displayed in the Expression Builder’s visual interface, and the Expression Preview is a great reference for learning to write more advanced expressions.

This Expression Builder screenshot shows the example compound expression described earlier. Compound expressions are easier to scan when displayed in the Expression Builder’s visual interface.

![Example rule configuration visible in the Expression Builder](~/assets/images/load-balancing/rules-builder-1.png)

The **Expression Preview** displays the expression in text:

```sql
(http.request.uri.path contains "/content")
and (http.request.uri.query contains "webserver")
```

For a walkthrough, refer to [Creating Load Balancing rules](/load-balancing/additional-options/load-balancing-rules/create-rules/).

### Expression Editor

The Expression Editor is a text-only interface for creating Load Balancing expressions. Although it lacks the visual simplicity of the Expression Builder, the Expression Editor supports advanced features such as support for grouping symbols (parentheses).

To access the Expression Editor in the **Traffic** app, click **Edit expression** in the **Create Custom Rule** dialog.

To return to the builder, click **Use expression builder**.

### Rules lists

Load Balancing Custom Rules does not support IP list operators.

# Custom load balancing rules



## How custom rules work

As with [WAF custom rules](/waf/custom-rules/), each load balancing custom rule is a combination of two elements: an [expression](/load-balancing/additional-options/load-balancing-rules/expressions/) and an [action](/load-balancing/additional-options/load-balancing-rules/actions/). Expressions define the criteria for an HTTP request to trigger an action. The action tells Cloudflare how to handle the request.

You can [create Load Balancing rules](/load-balancing/additional-options/load-balancing-rules/create-rules/) whenever you create or edit a load balancer in **Load Balancing**.

When building expressions for Load Balancing rules, refer to [Supported fields and operators](/load-balancing/additional-options/load-balancing-rules/reference/) for definitions and usage.

## Availability

By default, non-Enterprise customers have **one** Load Balancing rule **per load balancer hostname**. For more rules, upgrade to [Enterprise](https://www.cloudflare.com/enterprise/).

## Limitations

At the moment, you cannot use Load Balancing rules with [Cloudflare Spectrum](/spectrum/about/load-balancer/).

Custom rules can override [Geo steering](/load-balancing/understand-basics/traffic-steering/steering-policies/geo-steering/) pool mappings for matched requests. Specify different region, country, or data center pools in the rule. Changing only the steering policy does not disable Geo steering. Cloudflare still resolves pools from the configured topology before applying that policy.

Custom rules do work alongside [pool sets](/load-balancing/understand-basics/traffic-steering/pool-sets/). Cloudflare evaluates pool sets first, then applies custom rule overrides on top of the result. A pool set that returns a fixed response is the complete response, so custom rules are not evaluated for that request.


# Supported fields and operators

The fields that are supported by load balancing rules depend on whether Cloudflare proxies the traffic going through your load balancer or not.

If you use the wrong set of fields, you might see unexpected behaviors. For best results, use the fields associated with your traffic's [proxy status](/load-balancing/understand-basics/proxy-modes/).

Also, some Load Balancing rules fields are available on the Expression Builder - as described in [Load Balancing expressions](/load-balancing/additional-options/load-balancing-rules/expressions/#working-with-expressions) - while others can only be configured manually, via API or [Expression Editor](/load-balancing/additional-options/load-balancing-rules/expressions/#expression-editor)

## Expression Builder field sets

Consider the following table to know how the fields available in the [Expression Builder](/load-balancing/additional-options/load-balancing-rules/expressions/#expression-builder) are grouped.

| Field Set                                                                     | Section in Expression Builder | Description                                                                      |
| ----------------------------------------------------------------------------- | ----------------------------- | -------------------------------------------------------------------------------- |
| [Fields supported regardless of proxy](#fields-supported-regardless-of-proxy) | `BOTH`                        | Values that are always accessible regardless of the load balancer proxy status.  |
| [Proxied-only fields](#proxied-only-fields)                                   | `PROXIED ONLY`                | Values accessible only when the load balancer is proxied.                        |
| [Unproxied-only fields](#unproxied-only-fields)                               | `NON-PROXIED ONLY`            | Values accessible only when the load balancer is not proxied (DNS-only traffic). |

![Choose load balancer fields based on the proxy status header](~/assets/images/load-balancing/proxy-status.png)

## Fields supported regardless of proxy

Regardless of your traffic [proxy status](/load-balancing/understand-basics/proxy-modes/), Load Balancing rules can access values for the following fields:

<table style="width:100%">
	<thead>
		<tr>
			<th style="width:40%">Field</th>
			<th style="width:20%">Name in Expression Builder</th>
			<th>Description</th>
		</tr>
	</thead>
	<tbody>
		<tr id="field-cf-load-balancer-name">
			<td valign="top">
				<code>cf.load_balancer.name</code>
				<br />
				`Bytes`
			</td>
			<td>
				<code>Load Balancer Name</code>
			</td>
			<td>
				<p>Represents the name of the load balancer executing these rules.</p>
				<p>
					Example value:
					<br />
					<code class="InlineCode">lb.example.com</code>
				</p>
			</td>
		</tr>
		<tr id="field-cf-load-balancer-region">
			<td valign="top">
				<code>cf.load_balancer.region</code>
				<br />
				`Bytes`
			</td>
			<td>
				<code>Load Balancer Region</code>
			</td>
			<td>
				<p>
					Provides the{" "}
					<a href="/load-balancing/reference/region-mapping-api/#list-of-load-balancer-regions">
						region name
					</a>{" "}
					of the data center processing the request.
				</p>
				<p>
					Example value:
					<br />
					<code class="InlineCode">ENAM</code>
				</p>
			</td>
		</tr>
		<tr id="field-ip-src">
			<td valign="top">
				<code>ip.src</code>
				<br />
				`IP address`
			</td>
			<td>
				<code>IP Source Address</code>
			</td>
			<td>
				<p>
					If proxied, this field provides the client TCP IP address, which may
					be adjusted to reflect the actual address of the client by using HTTP
					headers such as <code>X-Forwarded-For</code> or <code>X-Real-IP</code>
					.
				</p>
				<p>
					If unproxied (DNS-only), this field provides the ECS source address,
					if available. If not available, it provides the client resolver IP
					address.
				</p>
				<p>
					<strong>Deprecation Warning:</strong> In the future, this field will
					always be set to the client resolver IP address for unproxied
					requests. To check for the presence of ECS and use the ECS IP, see the
					fields{" "}
					<a href="#field-dns-rr-opt-client">
						<code>dns.rr.opt.client</code>
					</a>{" "}
					and{" "}
					<a href="#field-dns-rr-opt-client-addr">
						<code>dns.rr.opt.client.addr</code>
					</a>
					, respectively.
				</p>
				<p>
					Example value:
					<br />
					<code class="InlineCode">1.2.3.4</code>
				</p>
			</td>
		</tr>
		<tr id="field-asnum">
			<td valign="top">
				<code>ip.src.asnum</code>
				<br />
				`Number`
			</td>
			<td>
				<code>AS Number</code>
			</td>
			<td>
				<p>
					The 16-bit or 32-bit integer representing the Autonomous System (AS)
					number associated with the client IP address.
				</p>
				<p>
					Example value:
					<br />
					<code class="InlineCode">13335</code>
				</p>
			</td>
		</tr>
	</tbody>
</table>

## Proxied-only fields

If your traffic is proxied through Cloudflare, you have access to all the fields listed under [Fields supported regardless of proxy](#fields-supported-regardless-of-proxy) in addition to the following fields:

Many of these fields are referenced from the [Rules language documentation](/ruleset-engine/rules-language/fields/reference/).

<table style="width:100%">
  <thead>
    <tr>
      <th style="width:40%">Field</th>
      <th style="width:20%">Name in Expression Builder</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr id="field-http-cookie">
      <td valign="top"><a href="/ruleset-engine/rules-language/fields/reference/http.cookie/"><code>http.cookie</code></a><br />`String`</td>
      <td>(<a href="/load-balancing/additional-options/load-balancing-rules/expressions/#expression-editor">Manual entry only</a>)</td>
      <td>
        <p>Represents the entire cookie as a string.</p>
        <p>
        Example value:
        <br /><code class="InlineCode">session=8521F670545D7865F79C3D7BEDC29CCE;-background=light</code>
        </p>
      </td>
    </tr>
    <tr id="field-http-host">
      <td valign="top"><a href="/ruleset-engine/rules-language/fields/reference/http.host/"><code>http.host</code></a><br />`String`</td>
      <td>(<a href="/load-balancing/additional-options/load-balancing-rules/expressions/#expression-editor">Manual entry only</a>)</td>
      <td>
        <p>Represents the hostname used in the full request URI.</p>
        <p>
        Example value:
        <br /><code class="InlineCode">www.example.org</code>
        </p>
      </td>
    </tr>
    <tr id="field-http-referer">
      <td valign="top"><a href="/ruleset-engine/rules-language/fields/reference/http.referer/"><code>http.referer</code></a><br />`String`</td>
      <td>(<a href="/load-balancing/additional-options/load-balancing-rules/expressions/#expression-editor">Manual entry only</a>)</td>
      <td>
        <p>Represents the HTTP Referer request header, which contains the address of the web page that linked to the currently requested page.</p>
        <p>
        Example value:
        <br /><code class="InlineCode">Referer: htt&shy;ps://developer.example.org/en-US/docs/Web/JavaScript</code>
        </p>
      </td>
    </tr>
    <tr id="field-http-request-headers">
      <td valign="top"><a href="/ruleset-engine/rules-language/fields/reference/http.request.headers/"><code>http.request.headers</code></a><br />`Map<Array<String>>`</td>
      <td><code>Header</code></td>
      <td>
        <p>Represents HTTP request headers as a Map (or associative array).</p>
        <p>The keys of the associative array are the names of HTTP request headers <strong>converted to lowercase</strong>.</p>
        <p>When there are repeating headers, the array includes them in the order they appear in the request.</p>
        <p>
        <em><em>Decoding:</em></em> no decoding performed
        <br /><em>Whitespace:</em> preserved
        <br /><em>Non-ASCII:</em> preserved
        </p>
        <p>
        Example:
        <br /><code class="InlineCode">any(http.request.headers["content-type"][*] == "application/json")</code>
        </p>
        <p>
        Example value:
        <br /><code class="InlineCode">`{"content-type": ["application/json"]}`</code>
        </p>
      </td>
    </tr>
    <tr id="field-http-request-method">
      <td valign="top"><a href="/ruleset-engine/rules-language/fields/reference/http.request.method/"><code>http.request.method</code></a><br />`String`</td>
      <td><code>Request Method</code></td>
      <td>
        <p>Represents the HTTP method, returned as a string of uppercase characters.</p>
        <p>
        Example value:
        <br /><code class="InlineCode">GET</code>
        </p>
      </td>
    </tr>
    <tr id="field-http-request-timestamp-sec">
      <td valign="top"><a href="/ruleset-engine/rules-language/fields/reference/http.request.timestamp.sec/"><code>http.request.timestamp.sec</code></a><br />`Integer`</td>
      <td><code>Timestamp</code></td>
      <td>
        <p>Represents the timestamp when Cloudflare received the request, expressed as Unix time in seconds. This value is 10 digits long.</p>
        <p>
        Example value:
        <br /><code class="InlineCode">1484063137</code>
        </p>
      </td>
    </tr>
    <tr id="field-http-request-uri">
      <td valign="top"><a href="/ruleset-engine/rules-language/fields/reference/http.request.uri/"><code>http.request.uri</code></a><br />`String`</td>
      <td><code>URI</code></td>
      <td>
        <p>Represents the URI path and query string of the request.</p>
        <p>
        Example value:
        <br /><code class="InlineCode">/articles/index?section=539061&expand=comments</code>
        </p>
      </td>
    </tr>
    <tr id="field-http-request-uri-args">
      <td valign="top"><a href="/ruleset-engine/rules-language/fields/reference/http.request.uri.args/"><code>http.request.uri.args</code></a><br />`Map<Array<String>>`</td>
      <td>(<a href="/load-balancing/additional-options/load-balancing-rules/expressions/#expression-editor">Manual entry only</a>)</td>
      <td>
        <p>Represents the HTTP URI arguments associated with a request as a Map (associative array).</p>
        <p>When an argument repeats, then the array contains multiple items in the order they appear in the request.</p>
        <p>
        The values are not pre-processed and retain the original case used in the request.
        </p>
        <p>
        <em>Decoding:</em> no decoding performed
        <br /><em>Non-ASCII:</em> preserved
        </p>
        <p>
        Example:
        <br /><code class="InlineCode">any(http.request.uri.args["search"][*] == "red+apples")</code>
        </p>
        <p>
        Example value:
        <br /><code class="InlineCode">`{"search": ["red+apples"]}`</code>
        </p>
      </td>
    </tr>
    <tr id="field-http-request-uri-args-names">
      <td valign="top"><a href="/ruleset-engine/rules-language/fields/reference/http.request.uri.args.names/"><code>http.request.uri.args.names</code></a><br />`Array<String>`</td>
      <td>(<a href="/load-balancing/additional-options/load-balancing-rules/expressions/#expression-editor">Manual entry only</a>)</td>
      <td>
        <p>Represents the names of the arguments in the HTTP URI query string. The names are not pre-processed and retain the original case used in the request.</p>
        <p>When a name repeats, the array contains multiple items in the order that they appear in the request.</p>
        <p>
        <em>Decoding:</em> no decoding performed
        <br /><em>Non-ASCII:</em> preserved
        </p>
        <p>
        Example:
        <br /><code class="InlineCode">any(http.request.uri.args.names[*] == "search")</code>
        </p>
        <p>
        Example value:
        <br /><code class="InlineCode">["search"]</code>
        </p>
      </td>
    </tr>
    <tr id="field-http-request-uri-args-values">
      <td valign="top"><a href="/ruleset-engine/rules-language/fields/reference/http.request.uri.args.values/"><code>http.request.uri.args.values</code></a><br />`Array<String>`</td>
      <td>(<a href="/load-balancing/additional-options/load-balancing-rules/expressions/#expression-editor">Manual entry only</a>)</td>
      <td>
        <p>Represents the values of arguments in the HTTP URI query string. The values are not pre-processed and retain the original case used in the request. They are in the same order as in the request.</p>
        <p>Duplicated values are listed multiple times.</p>
        <p>
        <em>Decoding:</em> no decoding performed
        <br /><em>Non-ASCII:</em> preserved
        </p>
        <p>
        Example:
        <br /><code class="InlineCode">any(http.request.uri.args.values[*] == "red+apples")</code>
        </p>
        <p>
        Example value:
        <br /><code class="InlineCode">["red+apples"]</code>
        </p>
      </td>
    </tr>
    <tr id="field-http-request-uri-path">
      <td valign="top"><a href="/ruleset-engine/rules-language/fields/reference/http.request.uri.path/"><code>http.request.uri.path</code></a><br />`String`</td>
      <td><code>URI Path</code></td>
      <td>
        <p>Represents the URI path of the request.</p>
        <p>
        Example value:
        <br /><code class="InlineCode">/articles/index</code>
        </p>
      </td>
    </tr>
    <tr id="field-http-request-uri-query">
      <td valign="top"><a href="/ruleset-engine/rules-language/fields/reference/http.request.uri.query/"><code>http.request.uri.query</code></a><br />`String`</td>
      <td><code>URI Query</code></td>
      <td>
        <p>Represents the entire query string, without the <code class="InlineCode">?</code> delimiter.</p>
        <p>
        Example value:
        <br /><code class="InlineCode">section=539061&expand=comments</code>
        </p>
      </td>
    </tr>
    <tr id="field-http-request-version">
      <td valign="top"><a href="/ruleset-engine/rules-language/fields/reference/http.request.version/"><code>http.request.version</code></a><br />`String`</td>
      <td><code>HTTP Version</code></td>
      <td>
        <p>Represents the version of the HTTP protocol used. Use this field when you require different checks for different versions.</p>
        <p>
        Example Values:
            <ul>
              <li><code class="InlineCode">HTTP/1.1</code></li>
              <li><code class="InlineCode">HTTP/3</code></li>
            </ul>
        </p>
      </td>
    </tr>
  </tbody>
</table>

## Unproxied-only fields

If your traffic is not proxied through Cloudflare, you have access to all the fields listed under [Fields supported regardless of proxy](#fields-supported-regardless-of-proxy) in addition to the following fields:

<table style="width:100%">
	<thead>
		<tr>
			<th style="width:40%">Field</th>
			<th style="width:20%">Name in Expression Builder</th>
			<th>Description</th>
		</tr>
	</thead>
	<tbody>
		<tr id="field-dns-qry-name">
			<td valign="top">
				<code>dns.qry.name</code>
				<br />
				`Bytes`
			</td>
			<td>
				<code>Query Name</code>
			</td>
			<td>
				<p>Represents the query name asked.</p>
				<p>
					Example value:
					<br />
					<code class="InlineCode">example.com.</code>
				</p>
			</td>
		</tr>
		<tr id="field-dns-qry-name-len">
			<td valign="top">
				<code class>dns.qry.name.len</code>
				<br />
				`Integer`
			</td>
			<td>
				<code>Query Name Length</code>
			</td>
			<td>
				<p>Represents the length in bytes of the query name.</p>
				<p>
					Example value:
					<br />
					<code class="InlineCode">123</code>
				</p>
			</td>
		</tr>
		<tr id="field-dns-qry-qu">
			<td valign="top">
				<code>dns.qry.qu</code>
				<br />
				`Boolean`
			</td>
			<td>
				<code>Question</code>
			</td>
			<td>
				<p>
					When <code>true</code>, this field indicates that the received DNS
					message was a question.
				</p>
			</td>
		</tr>
		<tr id="field-dns-qry-type">
			<td valign="top">
				<code>dns.qry.type</code>
				<br />
				`Integer`
			</td>
			<td>
				<code>Query Type</code>
			</td>
			<td>
				<p>
					Represents the numeric value of the{" "}
					<a href="https://en.wikipedia.org/wiki/List_of_DNS_record_types">
						DNS query type
					</a>
					.
				</p>
				<p>Example Values:</p>
				<ul>
					<li>
						<code class="InlineCode">1</code>&nbsp;(A record)
					</li>
					<li>
						<code class="InlineCode">28</code>&nbsp;(AAAA record)
					</li>
				</ul>
			</td>
		</tr>
		<tr id="field-dns-rr-opt-client">
			<td valign="top">
				<code class>dns.rr.opt.client</code>
				<br />
				`Boolean`
			</td>
			<td>
				(
				<a href="/load-balancing/additional-options/load-balancing-rules/expressions/#expression-editor">
					Manual entry only
				</a>
				)
			</td>
			<td>
				<p>
					When <code>true</code>, this field indicates that the EDNS Client
					Subnet (ECS) address was sent with the DNS request.
				</p>
			</td>
		</tr>
		<tr id="field-dns-rr-opt-client-addr">
			<td valign="top">
				<code class>dns.rr.opt.client.addr</code>
				<br />
				`String`
			</td>
			<td>
				(
				<a href="/load-balancing/additional-options/load-balancing-rules/expressions/#expression-editor">
					Manual entry only
				</a>
				)
			</td>
			<td>
				<p>
					If present, this field represents the ECS address sent with the DNS
					request.
				</p>
				<p>
					Example value:
					<br />
					<code class="InlineCode">1.2.3.0</code>
				</p>
			</td>
		</tr>
	</tbody>
</table>

## Operators and grouping symbols

- **Comparison operators** specify how values defined in an expression must relate to the actual HTTP request value for the expression to return true.

- **Logical operators** combine two expressions to form a compound expression and use order of precedence to determine how an expression is evaluated.

- **Grouping symbols** allow you to organize expressions, enforce operator precedence, and nest expressions.

For examples and usage, refer to [Operators and grouping symbols](/ruleset-engine/rules-language/operators/) in the Rules language documentation.

# Enable

Load balancing is an add-on for your account, meaning your account needs a [billing profile](/billing/get-started/create-billing-profile/).

To enable [Load Balancing](https://dash.cloudflare.com/?to=/:account/:zone/traffic/load-balancing):

1. In the Cloudflare dashboard, go to the **Load Balancing** page.

   

https://dash.cloudflare.com/?to=/:account/load-balancing

2. Select **Enable Load Balancing** in the **Status** column.
3. Choose your plan options and confirm payment.


# Get started

Get started with load balancing in one of two ways:

* [Quickstart](/load-balancing/get-started/quickstart/): Get up and running quickly with Load Balancing.
* [Learning path](/learning-paths/load-balancing/concepts/): Check an in-depth walkthrough for how to plan and set up a load balancer.

# Quickstart


Get up and running quickly with Load Balancing. For more in-depth explanations, refer to the [Learning path](/learning-paths/load-balancing/concepts/).

<br />

---

## Before you begin

Make sure you:

- Have access to multiple endpoints (origin servers, private or public IP addresses, virtual IP addresses (VIPs), etc), either physical or cloud-based.
- Have access to Load Balancing, available as an [add-on](/load-balancing/get-started/enable-load-balancing/) for any type of account.
- Have test and production hostnames that are covered by [SSL/TLS certificates](/load-balancing/load-balancers/dns-records/#ssltls-coverage).

## Create a monitor

 

### Dashboard

<strong>Set up the monitor</strong>

<strong>Prepare your servers</strong>

  

### API

<strong>Set up the monitor</strong>

<strong>Prepare your servers</strong>

 

## Create pools

 

### Dashboard

### API

 

## Confirm pool health

### Unexpected health status

## Create a load balancer on a test subdomain

 

### Dashboard

 

### API

 

## Optional - Review load balancing analytics

As you send sample requests to your test domain, review the [load balancing analytics](/load-balancing/reference/load-balancing-analytics/) page to make sure your load balancer is distributing requests like you were expecting.

## Route production traffic

## Optional - Next steps

Your load balancer should be receiving production traffic (and you can confirm this by reviewing the [analytics](/load-balancing/reference/load-balancing-analytics/)).

Though your product is officially set up, you may want to consider the following suggestions.

### Usage-based notifications

### Additional configuration options

You may want to further customize how your load balancer routes traffic or integrate your load balancer with other Cloudflare products:


# Common configurations

Consider the following sections to understand how to achieve some commonly used load balancer configurations.

This page assumes you understand the Cloudflare [Load Balancing components](/load-balancing/understand-basics/load-balancing-components/) and how to create and edit each of them.

## Active - Passive Failover

An **active-passive failover** sends traffic to the endpoints in your active pool until a failure threshold (configurable) is reached. At the point of failure, your load balancer then redirects traffic to the passive pool.

This setup ensures uninterrupted service and helps with planned outages, but it might lead to slower traffic overall.

To set up a load balancer with **active-passive failover**:

1. Create a load balancer with two pools (`primary` and `secondary`).
2. In the list of pools, set the following order:
   1. `primary`
   2. `secondary`
3. For **Traffic Steering**, select [**Off**](/load-balancing/understand-basics/traffic-steering/steering-policies/standard-options/#off---failover).

With this setup, your load balancer will direct all traffic to `primary` until `primary` has fewer available endpoints than specified in its **Health Threshold**. Only then will your load balancer direct traffic to `secondary`.

In the event that all pools are marked down, Cloudflare uses the **fallback pool**, which is the option of last resort for successfully sending traffic to an endpoint. Since the fallback pool is a last resort, its health is not taken into account, and Cloudflare reports its status as **No Health**. You can select the fallback pool via the API or in the Cloudflare dashboard. For more on working with fallback pools, refer to [Pool-level steering](/load-balancing/understand-basics/traffic-steering/steering-policies/).

## Active - Active Failover

An **active-active failover** distributes traffic to endpoints in the same pool until the pool reaches its failure threshold (configurable). At the point of failure, your load balancer would then re-direct traffic to the **fallback pool**.

This setup speeds up overall requests, but is more vulnerable to planned or unplanned outages.

To set up a load balancer with **active-active failover**, either:

* Create a load balancer with a single pool (`primary`) with multiple endpoints (`endpoint-1` and `endpoint-2`) and set the same [**Weight**](/load-balancing/understand-basics/traffic-steering/origin-level-steering/#weights) for each endpoint.
* Create a load balancer with two pools (`primary` and `secondary`) and — for [**Traffic Steering**](/load-balancing/understand-basics/traffic-steering/steering-policies/) — select any option except for **Off**.

:::note

For more background reading on server failover and common configurations, refer to [our Learning Center](https://www.cloudflare.com/learning/performance/what-is-server-failover/).

:::


# Manage load balancers


 <br />

For more details about load balancers, refer to [Load balancers](/load-balancing/load-balancers/).

## Create a load balancer

 

### Dashboard

 

### API

 

### Sharing your load balancer with other sites

You can share your load balancer with other sites in your account by [creating a canonical name (`CNAME`) record](/dns/manage-dns-records/how-to/create-dns-records/). This is useful for sharing configurations with multiple other domains so you do not have to create new load balancers for each site.

You can also configure separate load balancers for each domain and reuse monitors and pools. This is especially useful for changing the failover order for different domains, such as when your `example.co.uk` server has a different failover priority from `example.com` or `example.com.au`.

:::note

Sharing load balancers across sites is only supported if the target zone is on a [full DNS setup](/dns/zone-setups/full-setup/). It is not supported if the target zone is on a `CNAME` setup.

:::

---

## Edit a load balancer

 

### Dashboard

To edit a load balancer in the dashboard:

1. Go to **Load Balancing**.
2. On a specific load balancer, select **Edit**.
3. While going through the [creation workflow](#create-a-load-balancer), update settings as needed.
4. On the **Review** step, select **Save**.

 

### API

When you edit a load balancer with the API, your request type depends on how much you want to edit.

To update specific settings without having to resubmit the entire configuration, use a [PATCH](/api/resources/load_balancers/methods/edit/) request. For broader changes, use a [PUT](/api/resources/load_balancers/methods/update/) request.

 

---

## Delete a load balancer

If you delete or disable a load balancer, your endpoint's response to requests will depend on your [existing DNS records](/load-balancing/load-balancers/dns-records/#disabling-a-load-balancer).

 

### Dashboard

To delete a load balancer in the dashboard:

1. Go to **Load Balancing**.
2. On a specific load balancer, click **Delete**.

 

### API

To delete a load balancer using the API, send a [DELETE](/api/resources/load_balancers/methods/delete/) request.

 

---

## Set up alerts

You can configure alerts to receive notifications for changes in the health status of your pools or endpoints.


# DNS records

When you [create a load balancer](/load-balancing/load-balancers/create-load-balancer/), Cloudflare automatically creates an LB DNS record for the specified **Hostname**. This functionality allows you to use a hostname with or without an existing DNS record. Private load balancers do not receive an automatic DNS record. Instead, you can configure a hostname using your internal DNS system or by applying a [Gateway Firewall override](/cloudflare-one/traffic-controls/dns-policies/#override) to a hostname.

## Supported records

For customers on non-Enterprise plans, Cloudflare supports load balancing for `A`, `AAAA`, and `CNAME` records.

For customers on Enterprise plans, Cloudflare supports load balancing for `A`, `AAAA`, `CNAME`, **MX**, and **SRV** records.

## Priority order

For hostnames with existing DNS records, the LB record takes precedence when it is more or equally specific:

- **Scenario 1**:
  - **A, AAAA, or CNAME**: `x.example.com`
  - **LB record**: `x.example.com`
  - **Outcome**: LB record takes precedence because it is as specific as the DNS record.

- **Scenario 2**:
  - **A, AAAA, or CNAME**: `y.example.com`
  - **LB record**: `*.example.com` (wildcard record)
  - **Outcome**: DNS record takes precedence because it is more specific.

- **Scenario 3**:
  - **A, AAAA, or CNAME**: `*.example.com`
  - **LB record**: `*.example.com`
  - **Outcome**: LB record takes precedence because it is as specific as the DNS record.

:::note

This behavior only applies to [supported records](#supported-records) (determined by your plan type).

:::

If the DNS record points to a [SaaS provider](/cloudflare-for-platforms/cloudflare-for-saas/) and an active [custom hostname](/cloudflare-for-platforms/cloudflare-for-saas/domain-support/) exists, the custom hostname will take precedence over the Load Balancing record:

- **Scenario 4**:
  - **CNAME**: `x.example.com` with target to a Cloudflare for SaaS provider
  - **LB record**: `x.example.com`
  - **Active custom hostname on the SaaS provider side**: `x.example.com`
  - **Outcome**: Custom hostname takes precedence.

## Disabling a load balancer

When you disable a load balancer, requests to a specific hostname depend on your existing DNS records:

- If you have existing DNS records, these records will be served.
- If there are no existing records, requests to the hostname will fail.

In both cases, disabling your load balancer prevents traffic from going to any associated endpoint or fallback pools.

If you already have an existing `A`, `AAAA`, or `CNAME` record, be aware that the change may take some time to propagate due to [Time to Live (TTL)](/dns/manage-dns-records/reference/ttl/) and any record changes is affected, as your local DNS cache may take longer to update.

## SSL/TLS coverage

Due to internal limitations, on [Partial (CNAME) setup](/dns/zone-setups/partial-setup/) the Cloudflare [Universal SSL certificates](/ssl/edge-certificates/universal-ssl/) do not cover load balancing hostnames by default. This behavior will be corrected in the future.

As a current workaround for a domain or first-level subdomain (`lb.example.com`), create a [proxied `CNAME`/`A`/`AAAA` record](/dns/manage-dns-records/how-to/create-dns-records/) for that hostname.

For example, if your load balancer hostname was `lb.example.com`, you could create the following record solely for the purpose of SSL/TLS coverage.

| Type | Name | IPv4 address | Proxy status |
| ---- | ---- | ------------ | ------------ |
| A    | `lb` | `192.0.2.1`  | Proxied      |

Based on the [priority order](#priority-order), it would not receive any traffic because it is as equally specific as the LB hostname.

To get coverage for any deeper subdomain (`lb.dev.example.com`), purchase an [advanced certificate](/ssl/edge-certificates/advanced-certificate-manager/).

# Load balancers



:::note

For an overview of how the Cloudflare Load Balancing solution works, refer to [Load Balancing components](/load-balancing/understand-basics/load-balancing-components/). For more background information on what load balancers are, refer to the Cloudflare [Learning Center](https://www.cloudflare.com/learning/performance/what-is-load-balancing/).

:::

---

## Common configurations

For suggestions, refer to [Common load balancer configurations](/load-balancing/load-balancers/common-configurations/).

## Public vs. Private Load Balancers

Public Load Balancers are designed to handle traffic from the public Internet. When deployed, they automatically receive a hostname, making them immediately accessible. These load balancers can direct traffic to a range of destinations, including public hostnames, public IP addresses, and private IP addresses.

Private Load Balancers, in contrast, are meant for internal use within private networks. They do not automatically receive a hostname, but one can be assigned via Gateway Firewall Policies or through an internal DNS system. Private Load Balancers only accept traffic over a private network on-ramp, such as [the Cloudflare One Client](/warp-client/) or [Cloudflare WAN](/cloudflare-wan/). They are capable of forwarding traffic exclusively to private IP addresses.

## Load balancing and existing DNS records

For details about DNS records, refer to [DNS records for load balancing](/load-balancing/load-balancers/dns-records/).

## HTTP keep-alive (persistent HTTP connection)

Cloudflare maintains keep-alive connections to improve performance and reduce cost of recurring TCP connects in the request transaction as Cloudflare proxies customer traffic from its edge network to the site's origin.

Ensure HTTP Keep-Alive connections are enabled on your origin. Cloudflare reuses open TCP connections for up to 15 minutes (900 seconds) after the last HTTP request. Origin web servers close TCP connections if too many are open. HTTP Keep-Alive helps avoid premature reset of connections for requests proxied by Cloudflare.

### Session cookies

**When using HTTP cookies to track and bind user sessions to a specific server**, configure [Session Affinity](/load-balancing/understand-basics/session-affinity/) to parse HTTP requests by cookie header. Doing so directs each request to the correct application server even when HTTP requests share the same TCP connection due to keep-alive.

**For example, F5 BIG-IP load balancers set a session cookie at the beginning of a TCP connection** (if none exists) and then ignore all cookies from subsequent HTTP requests on the same TCP connection. This tends to break session affinity because Cloudflare sends multiple HTTP sessions on the same TCP connection. Configuring the load balancer to parse HTTP requests by cookie headers avoids this issue.

---

## Create load balancers

For step-by-step guidance, refer to [Create a load balancer](/load-balancing/load-balancers/create-load-balancer/).

---

## Properties

For an up-to-date list of load balancer properties, refer to [Load balancer properties](/api/resources/load_balancers/methods/get/) in the Cloudflare API documentation.

---

## API commands

The Cloudflare API supports the following commands for load balancers.

| Command                                                                         | Method   | Endpoint                             |
| ------------------------------------------------------------------------------- | -------- | ------------------------------------ |
| [Create Load Balancer](/api/resources/load_balancers/methods/create/)           | `POST`   | `/zones/:zone_id/load_balancers`     |
| [Delete Load Balancer](/api/resources/load_balancers/methods/delete/)           | `DELETE` | `/zones/:zone_id/load_balancers/:id` |
| [List Load Balancers](/api/resources/load_balancers/methods/list/)              | `GET`    | `/zones/:zone_id/load_balancers`     |
| [Load Balancer Details](/api/resources/load_balancers/methods/get/)             | `GET`    | `/zones/:zone_id/load_balancers/:id` |
| [Overwrite specific properties](/api/resources/load_balancers/methods/edit/)    | `PATCH`  | `/zones/:zone_id/load_balancers/:id` |
| [Overwrite entire Load Balancer](/api/resources/load_balancers/methods/update/) | `PUT`    | `/zones/:zone_id/load_balancers/:id` |


# Manage monitors



For more details about monitors, refer to [Monitors](/load-balancing/monitors/).

---

## Retry timing

When a health check times out, Cloudflare sends retries immediately — they do not wait for the next interval. The `retries` setting defines the number of additional attempts after the initial check. For example, with five retries:

- Total attempts: 1 (initial) + 5 (retries) = **6**
- With a 20 s timeout: Cloudflare marks the endpoint unhealthy after approximately 120 s (6 × 20 s)
- The configured interval (for example, 60 s) only applies between **successful** probe cycles, not between retries

---

## Create a monitor

 

### Dashboard

**Set up the monitor**

**Prepare your servers**

**Attach the monitor to a pool**

Once your monitor is created, you need to attach it to a pool:

1. Go to **Load Balancing**.

2. Select the **Pools** tab.

3. On a specific pool, select **Edit**.

4. Update the following information:
   - **Monitor**: Select your monitor.
   - **Health Monitor Regions:** Specifies geographic regions from which Cloudflare should send health monitor requests. Because of [how monitors check pool health](/load-balancing/monitors/#health-monitor-regions), selecting multiple regions could increase the load on your servers.
   - **Notification E-mail:** Contains email addresses that receive notifications (individual, mailing list address, PagerDuty address).

5. Select **Save**. The status of your health monitor will be _unknown_ until the results of the first check are available.

 

### API

**Set up the monitor**

**Prepare your servers**

**Attach the monitor to a pool**

Once your monitor is created, save its `id` property. Include this value in the `monitor` parameter when [creating your pool](/load-balancing/pools/create-pool/#create-a-pool).

 

---

## Edit a monitor

 

### Dashboard

To edit a monitor in the dashboard:

1. Go to **Load Balancing**.
2. Select **Monitors**.
3. On a specific monitor, select **Edit**.
4. Update settings as needed.
5. Select **Save**.

 

### API

When you edit a monitor with the API, your request type depends on how much you want to edit.

To update specific settings without having to resubmit the entire configuration, use a [PATCH](/api/resources/load_balancers/subresources/monitors/methods/edit/) request. For broader changes, use a [PUT](/api/resources/load_balancers/subresources/monitors/methods/update/) request.

 

---

## Delete a monitor

 

### Dashboard

To delete a monitor in the dashboard:

1. Go to **Load Balancing**.
2. Select the **Monitors** tab.
3. On a specific monitor, select **Delete**.

 

### API

To delete a monitor using the API, send a [DELETE](/api/resources/load_balancers/subresources/monitors/methods/delete/) request.


# Monitors



Health monitor requests that result in a status change for an endpoint are recorded as events in the Load Balancing event logs.

:::note

Health monitors associated with load balancers are different from standalone [Health Checks](/health-checks/). For an overview of how the Cloudflare Load Balancing solution works, refer to [Load Balancing components](/load-balancing/understand-basics/load-balancing-components/).

:::

---

## Properties

For an up-to-date list of monitor properties, refer to [Monitor properties](/api/resources/load_balancers/subresources/monitors/methods/list/) in our API documentation.

---

## Create monitors

For step-by-step guidance, refer to [Create monitors](/load-balancing/monitors/create-monitor/).

### Monitor Groups

Monitor Groups let you combine multiple health monitors into a single logical group to create more accurate, intelligent health checks for your applications. By aggregating results from several monitors, you can better reflect real application health and improve traffic steering resilience. For more details, refer to the [Monitor Groups](/load-balancing/monitors/monitor-groups/) documentation page.

---

## Health monitor regions

When you [attach a monitor to a pool](/load-balancing/monitors/create-monitor/#create-a-monitor), you can select multiple regions to increase reporting accuracy.

### Configurations

---

## IPv4 and IPv6 probe behavior

Health monitor probes use IPv4 by default. IPv6 probes are only sent if the endpoint address has no `A` records (only `AAAA`). Each endpoint receives one probe per interval — Cloudflare does not probe both IPv4 and IPv6 for the same endpoint.

To enforce probing over IPv6, set the endpoint address to either a raw IPv6 address or a hostname that only has `AAAA` records.

---

## Host header prioritization

The host headers used on health monitor requests can be configured either [on the monitor itself](/load-balancing/monitors/create-monitor/) or on the [endpoints within a pool](/load-balancing/pools/create-pool/).

When a host header is specified both on the monitor and on the endpoint, the host header configured on the endpoint takes precedence over the host header configured on the monitor.

When no host header is specified, Cloudflare uses the **Endpoint Address** configured on the endpoints as the host header for the health monitor requests.

For more details, refer to [Override HTTP Host headers](/load-balancing/additional-options/override-http-host-headers/).

---

## API commands

The Cloudflare API supports the following commands for monitors. Examples are given for user-level endpoint but apply to the account-level endpoint as well.

| Command                                                                                                      | Method   | Endpoint                                                   |
| ------------------------------------------------------------------------------------------------------------ | -------- | ---------------------------------------------------------- |
| [Create Monitor](/api/resources/load_balancers/subresources/monitors/methods/create/)                        | `POST`   | `accounts/:account_id/load_balancers/monitors`             |
| [Delete Monitor](/api/resources/load_balancers/subresources/monitors/methods/delete/)                        | `DELETE` | `accounts/:account_id/load_balancers/monitors/:id`         |
| [List Monitors](/api/resources/load_balancers/subresources/monitors/methods/list/)                           | `GET`    | `accounts/:account_id/load_balancers/monitors`             |
| [Monitor Details](/api/resources/load_balancers/subresources/monitors/methods/get/)                          | `GET`    | `accounts/:account_id/load_balancers/monitors/:id`         |
| [Overwrite specific properties](/api/resources/load_balancers/subresources/monitors/methods/edit/)           | `PATCH`  | `accounts/:account_id/load_balancers/monitors/:id`         |
| [Overwrite existing monitor](/api/resources/load_balancers/subresources/monitors/methods/update/)            | `PUT`    | `accounts/:account_id/load_balancers/monitors/:id`         |
| [Preview Monitor](/api/resources/load_balancers/subresources/monitors/subresources/previews/methods/create/) | `POST`   | `accounts/:account_id/load_balancers/monitors/:id/preview` |

## Supported protocols

The following table summarizes the different types of monitors available in Cloudflare Load Balancing, their monitoring types, and how each health check process evaluates the success criteria to determine endpoint health:

| Monitor type | Monitoring type    | Description                                                                                                                                                                                | Health check process                                                                                                                                                                                                                                                                                                                                                                                                                          | Success criteria                                                                                                                                   |
| ------------ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| HTTP/HTTPS   | Public and private | Used for HTTP and HTTPS endpoints with specific protocol attributes.                                                                                                                       | The probe is configured with settings and success criteria such as Method, Simulate Zone, Follow Redirects, Request Headers, and Response Body. The probe then evaluates the configured success criteria using the HTTP protocol. Throughout the configured timeout period, the TCP connection is kept active using [keep-alives](/fundamentals/reference/tcp-connections/#tcp-connections-and-keep-alives), even if no response is received. | Success is based on meeting the configured HTTP success criteria. No response within the configured timeout and retries is considered unhealthy.   |
| TCP          | Public and private | Checks TCP connectivity by attempting to open a connection to the endpoint.                                                                                                                | The monitor sends a TCP SYN message to the specified port. A successful health check requires receiving a SYN/ACK message to establish the connection. The connection is closed by sending a FIN or RST packet, or by receiving a FIN packet from the endpoint.                                                                                                                                                                               | Failure to establish a TCP connection within the configured timeout and retries is considered unhealthy.                                           |
| ICMP Ping    | Public and Tunnel | Confirms basic Layer 3 (L3) connectivity to the endpoint using ICMP. The endpoints need to be allowed to reply to ICMP packets and any intervening networking equipment must support ICMP. | The monitor sends an ICMP/ICMPv6 echo request (ping) and expects an ICMP/ICMPv6 echo reply from the endpoint.                                                                                                                                                                                                                                                                                                                                 | The endpoint must reply to the ICMP ping within the configured timeout and retries to be considered healthy.                                       |
| UDP-ICMP     | Public and Tunnel | UDP-ICMP monitor works by sending a UDP probe packet after ICMP Ping monitor completes as healthy.                                                                                         | After receiving a successful ICMP reply, the monitor sends a UDP probe packet to the endpoint. If no ICMP Port Unreachable message is received, the endpoint is considered healthy.                                                                                                                                                                                                                                                           | If the monitor receives an ICMP Port Unreachable message within the configured timeout and retries, the endpoint is considered unhealthy.          |
| SMTP         | Public             | Verifies SMTP availability at the application layer.                                                                                                                                       | The monitor establishes a TCP connection and sends an SMTP HELO command. It expects a reply with code 250. The monitor then sends an SMTP QUIT command, expecting a reply with code 221. At the end of each interval, the TCP connection is closed by sending a TCP FIN packet.                                                                                                                                                               | The endpoint must respond with correct SMTP codes (250 for HELO, 221 for QUIT) within the configured timeout and retries to be considered healthy. |


# Monitor Groups

Group multiple health monitors together to create sophisticated health checks for your applications, ensuring more intelligent and resilient traffic steering.

You can group multiple health monitors to build sophisticated health checks that more accurately reflect your application's true health. A Monitor Group allows you to combine several independent monitors, define aggregation logic, and use the collective result to determine the health of an origin pool.

Grouping multiple health monitors enables more intelligent and resilient failover. For example, you can require that both a general API gateway monitor and a specific login service monitor must be healthy for a pool to receive traffic.

## Availability

Monitor Groups are only available to customers on an Enterprise plan with the Load Balancing subscription.

Configuration is available via the [API](/api/resources/load_balancers/subresources/monitor_groups/methods/create/) only.

:::note
Pools assigned to a monitor group via the API will appear as **Not monitored** on the dashboard.
:::

## How it works

When you attach a Monitor Group to a pool, the health of that pool is determined by aggregating the results of all enabled monitors within the group.

The sections below explain how monitor groups influence health status, latency, and result handling.

## Endpoint health with Monitor Groups

A Monitor Group determines an endpoint's health using a combination of critical monitor overrides and quorum-based consensus.

**Critical Monitor Override** (`must_be_healthy`): You can designate a monitor as critical by setting `"must_be_healthy": true`. If a monitor with this setting fails its health check against an endpoint, that specific endpoint is immediately marked as unhealthy. This happens regardless of the status reported by other monitors in the group for that same endpoint. This provides a definitive override for essential services.

**Quorum-Based Health**: In the absence of a failure from a `must_be_healthy` monitor, an endpoint's health is determined by a quorum of all other active monitors.

- An endpoint is considered unhealthy only if more than 50% of its assigned monitors report it as unhealthy.
- Monitors marked as `"monitoring_only": true` are excluded from the quorum calculation. They will still run and can trigger notifications, but they do not vote on the endpoint's health status.
- Monitors marked as `disabled` will not send monitoring requests to any associated pool. They are also excluded from the quorum calculation.

This quorum system prevents an endpoint from being prematurely marked as unhealthy due to a transient failure from a single, non-critical monitor.

## Latency for Steering

For pools using Dynamic Steering, the pool's latency is calculated as the average latency of all its enabled, non-monitoring-only monitors. This aggregated RTT (Round Trip Time) value provides a more holistic view of an origin's performance and is used to make steering decisions.

## Result handling for different intervals

If monitors in a group have different check intervals, the group uses the last available result from each monitor until it is refreshed. For example, if one monitor runs every 10 seconds and another every 30 seconds, the 30-second monitor's result is considered valid for the full 30 seconds until its next run completes.

# Use Pages as an origin for Load Balancing


This tutorial is intended as an introductory example of how you can leverage Cloudflare's global traffic management.

The following sections will guide you through setting up an [active-passive failover](/load-balancing/load-balancers/common-configurations/#active---passive-failover) load balancer with [Cloudflare Pages](/pages/) as one of the endpoints, while also going into details about the Load Balancing dashboard workflow, and some important field values and troubleshooting.

## Use cases

This setup can be useful if you are migrating your production website or application to Pages or if you just want to have a backup or a personalized web page for when your primary origin goes down.

## Before you begin

Make sure you:

- Are familiar with the Cloudflare [Load Balancing components](/load-balancing/understand-basics/load-balancing-components/).
- Own a domain and use Cloudflare as a [primary DNS provider](/dns/zone-setups/full-setup/).
- Have [deployed a website or application](/pages/get-started/git-integration/) with Cloudflare Pages.
- Have [enabled Load Balancing](/load-balancing/get-started/enable-load-balancing/) in your account.

## Create health monitor

Although you can create all the components in the **Create Load Balancer** workflow, using the **Manage Monitors** and **Manage Pools** sections separately makes it easier to test and troubleshoot the configurations of each of these components before bringing them together in a load balancer.

Monitors define the criteria based on which an endpoint will be considered healthy or not. Start by setting up a monitor as follows.

1. In the Cloudflare dashboard, go to the **Load Balancing** page.

   

https://dash.cloudflare.com/?to=/:account/load-balancing

2. Select the **Monitors** tab and then **Create monitor**.
3. Give the monitor a descriptive name and confirm the other fields are filled in as the following:

| Field | Value |
| ----- | ----- |
| Type  | HTTP  |
| Path  | /     |
| Port  | 80    |

4. Under **Advanced health check settings**, keep the default values and enable the **Follow Redirects** option.

   When you are using a service like Cloudflare Pages, it is possible that requests from the health monitor - as well as the ones from your visitors - are redirected before reaching their destination. Enabling this option prevents the monitor from reporting an unhealthy endpoint when it actually has only been redirected (with a `301` code, for example).

:::note[Tip]

You can name the monitor after the parameters you have defined. For example: `HTTP - 200 - Follow Redirects`.

This way you can easily remember the criteria a certain monitor is using when you decide to attach it to other endpoints as well.
:::

5. Select **Save** to confirm.

## Create pools

Pools hold information about where the health monitor requests and your visitors requests will be directed to.

To support the [use cases](#use-cases) mentioned above, and assuming you only have one origin server for your production website and one for the Cloudflare Pages instance, create two pools with one endpoint each:

:::caution[Important]

The endpoint pointing to [Cloudflare Pages](/pages/) must have **host header** filled in with the project domain (`<project>.pages.dev`) for it to resolve correctly. You can find a reference table for correct setup in Step 8 below.

Failing to add the host header will result in [response code mismatch error](/load-balancing/troubleshooting/common-error-codes/#response-code-mismatch-error) for the monitor, and [Error 1000: DNS points to prohibited IP](/support/troubleshooting/http-status-codes/cloudflare-1xxx-errors/error-1000/) for visitors (if the load balancer is enabled despite the unhealthy monitor status).
:::

1. In the Cloudflare dashboard, go to the **Load Balancing** page.

   

https://dash.cloudflare.com/?to=/:account/load-balancing

2. Select the **Pools** tab and then **Create monitor**.

3. For the first pool, start by filling out the fields:

- A name for the pool (must be unique). Suggestion: `primary`
- A description to provide more details on the name. Suggestion: `production website`

4. Leave the choice for [**Endpoint Steering**](/load-balancing/understand-basics/traffic-steering/origin-level-steering/) as is. Since each pool will only have one endpoint, this steering method will not interfere in this case.

5. Add your origin server as an endpoint with the following information:

- A name for the endpoint (must be unique). Suggestion: `my-website`.
- The endpoint IP address or hostname.

  :::caution

  As exemplified in Step 8 below, when using Cloudflare as an endpoint, **do not** specify one of Cloudflare's anycast IP addresses. Because these IPs can change at any time, you should use a hostname instead.
  :::

- The endpoint [weight](/load-balancing/understand-basics/traffic-steering/origin-level-steering/#weights), which can be set to `1`. Since each pool will only have one endpoint, the endpoint weight will not make a difference in this case.
- A [hostname](/load-balancing/additional-options/override-http-host-headers/) by selecting **Add host header**.

  :::caution

  If your production website is hosted on a platform like Cloudflare Pages, where you have a default subdomain (`example.pages.dev`) and then configure a [custom domain](/pages/configuration/custom-domains) (`my-app.com`), you will need to add a host header to avoid failing the health monitor request.
  :::

6. Finish configuring the first pool with the following information:

- Leave the **Health Threshold** set to `1`. Since each pool will only have one endpoint, this is the only possible value for this field.
- Select the **Monitor** configured in the previous step.
- Select **Health Check Regions** to choose from which [locations](/load-balancing/monitors/#health-monitor-regions) Cloudflare should send monitor requests to periodically test the endpoint health.

7. Select **Save**

8. Repeat the process for the second pool using the following values:

| Field                      | Value                                     |
| -------------------------- | ----------------------------------------- |
| Pool name                  | `secondary`                               |
| Description                | `Pages version`                           |
| Endpoint steering          | `<default>`                               |
| Endpoint name              | `my-pages-website`                        |
| Endpoint address           | `<your custom domain or Pages subdomain>` |
| Weight                     | `1`                                       |
| Host (**Add host header**) | `<your custom domain or Pages subdomain>` |
| Health threshold           | `1`                                       |
| Monitor                    | `<monitor defined on previous step>`      |
| Health check regions       | `<select region of your choice>`          |

## Check the endpoints health status

Before setting up the load balancer:

1. In the Cloudflare dashboard, go to the **Load Balancing** page.

   

https://dash.cloudflare.com/?to=/:account/load-balancing

1. Go to the **Pools** tab.
1. Find the pools you created in the list and check if their status is `Healthy`. You might have to refresh the page.
1. Expand each pool entry to confirm that the health status for endpoints within them is also `Healthy`.

The basic principle is that, if both your production website and your Cloudflare Pages project are live and directly accessible via browser, the monitors should also be able to get a `200` code as HTTP response.

Revise your pools and monitor configurations to confirm they followed the instructions above. If you still find issues, refer to [Troubleshooting](/load-balancing/troubleshooting/common-error-codes/) or [FAQ](/load-balancing/troubleshooting/load-balancing-faq/#why-is-my-endpoint-or-pool-considered-unhealthy).

## Create load balancer

After confirming the endpoints and monitors are set up correctly and return the expected health status, create the load balancer:

1. In the Cloudflare dashboard, go to the **Load Balancing** page.

   

https://dash.cloudflare.com/?to=/:account/load-balancing

2. Select **Create load balancer**.

3. On the **Hostname** page, configure the following and select **Next**.
   - Enter a **Hostname**, which is the DNS name at which the load balancer is available. Suggestion: for now, you can just add a temporary hostname such as `lb` (so the complete field value would look like `lb.<your_domain>`).
   - Toggle the orange cloud icon to update the [proxy mode](/load-balancing/understand-basics/proxy-modes/), which affects how traffic is routed and which IP addresses are advertised.
   - Select your preferred option for [session affinity](/load-balancing/understand-basics/session-affinity/) and [adaptive routing](/load-balancing/understand-basics/adaptive-routing/).

4. On the **Add a Pool** page, configure the following and select **Next**.
   - Select the first pool you created previously and select **Add Pool**.
   - Do the same for the second pool and reorder them if needed. For the purposes of this tutorial, your production website pool would be the first (`primary`) and the Cloudflare Pages pool would be the second (`secondary`).
   - If needed, update the [**Fallback Pool**](/load-balancing/understand-basics/health-details/#fallback-pools). For the purposes of this tutorial, you can leave this pointing to your secondary pool.

5. On the **Monitors** page, review the monitors attached to your pools and the expected health status, and select **Next**.

6. On the **Traffic Steering** page, make sure **Off** is selected. This means the load balancer will follow the order established on the **Add a Pool** section (Step 3 above), achieving an [Active - Passive Failover](/load-balancing/load-balancers/common-configurations/#active---passive-failover) configuration.

7. For the purposes of this tutorial, leave the [**Custom Rules**](/load-balancing/additional-options/load-balancing-rules/) option empty.

8. On the **Review** page, review your configuration and select **Save as Draft**.

A DNS record of the type `LB` will be created under [**DNS** > **Records**](https://dash.cloudflare.com/?to=/:account/:zone/dns/records) with the hostname you have defined, and a corresponding load balancer will be added to [**Load Balancing**](https://dash.cloudflare.com/?to=/:account/load-balancing)

## Optional - Deploy on a test hostname

If you have used a temporary hostname for your load balancer, follow the steps below to deploy and test it.

1. In the Cloudflare dashboard, go to the **Load Balancing** page.

   

https://dash.cloudflare.com/?to=/:account/load-balancing

2. In the **Load Balancers** list, locate the load balancer you created under a test hostname (such as `lb`) and enable it.
3. On your browser, request the temporary hostname (`lb.example.com`). You should see the website or application hosted at your primary origin server.
4. Go back to the **Manage Load Balancers** list, select to expand the test load balancer, and disable the primary pool.
5. On a new incognito window of your browser, request the temporary hostname once again. You should see the website or application hosted at your secondary origin server this time.

   If you find issues, revise your pools, monitor, and load balancer configurations to confirm they followed the instructions above. Also refer to [Troubleshooting](/load-balancing/troubleshooting/common-error-codes/) or [FAQ](/load-balancing/troubleshooting/load-balancing-faq/) if needed.

:::caution[Important]

After you confirm everything is working correctly, make sure you re-enable the pools within the load balancer.
:::

## Route production traffic to load balancer

Now that you have set up your load balancer and verified everything is working correctly, you can put the load balancer on a live domain or subdomain:

1. Confirm that your production hostname has the correct [priority order](/load-balancing/load-balancers/dns-records/#priority-order) of DNS records and is covered by an [SSL/TLS certificate](/load-balancing/load-balancers/dns-records/#ssltls-coverage).

   If you have an Enterprise account, also evaluate your application for any excluded paths. For example, you might not want the load balancer to distribute requests directed at your `/admin` path. For any exceptions, set up an [Origin rule](/rules/origin-rules/features/#dns-record).

2. Configure your load balancer to receive production traffic by editing the **Hostname** of your existing load balancer.


# Manage pools



For more background information on pools, refer to [Pools](/load-balancing/pools/).

:::caution

{" "}

:::

---

## Endpoint address uniqueness

Within a single pool, each endpoint address must be unique. Endpoints cannot share the same IP address, even when they use different ports or virtual networks. To use overlapping IP addresses, assign the endpoints to different pools.

---

## Create a pool

 

### Dashboard

 

### API

 

---

## Edit a pool

 

### Dashboard

To edit a pool in the dashboard:

1. Go to **Load Balancing**.
2. Select the **Pools** tab.
3. On a specific pool, select **Edit**.
4. Update settings as needed.
5. Select **Save**.

 

### API

When you edit a pool with the API, your request type depends on how much you want to edit.

To update specific settings without having to resubmit the entire configuration, use a [PATCH](/api/resources/load_balancers/subresources/pools/methods/edit/) request. For broader changes, use a [PUT](/api/resources/load_balancers/subresources/pools/methods/update/) request.

 

---

## Delete a pool

You cannot delete pools that are in use by load balancers. This includes [geo steering regions](/load-balancing/understand-basics/traffic-steering/steering-policies/geo-steering/#region-steering) pools, pools referenced by a [pool set](/load-balancing/understand-basics/traffic-steering/pool-sets/), as well as [fallback pools](/load-balancing/understand-basics/health-details/#fallback-pools).

If you get an error when trying to delete a pool, consider the hostnames listed in the error and [edit the respective load balancers](/load-balancing/load-balancers/create-load-balancer/), making sure to remove all references to the pool.

:::note

If the pool is referenced by geo steering, the configuration is **not** automatically removed when you change to a different **Traffic Steering** method. To make sure you remove it, select **Geo Steering**, remove the pool, and then apply and save any other necessary changes.
:::

 

### Dashboard

To delete a pool in the dashboard:

1. Go to **Load Balancing**.
2. Select the **Pools** tab.
3. On a specific pool, select **Delete**.

 

### API

To delete a pool using the API, send a [DELETE](/api/resources/load_balancers/subresources/pools/methods/delete/) request.

 

---

## Set up alerts

You can configure alerts to receive notifications for changes in the status of your pools.


# Pools



For more details about how endpoints and pools become unhealthy, refer to [Endpoint and pool health](/load-balancing/understand-basics/health-details/).

:::caution

:::

---

## Properties

For an up-to-date list of pool properties, refer to [Pool properties](/api/resources/load_balancers/subresources/pools/methods/list/) in our API documentation.

---

## Create pools

For step-by-step guidance, refer to [Create pools](/load-balancing/pools/create-pool/).

---

## Per-endpoint Host header override

When your application needs specialized routing (`CNAME` setup or custom hosts like Heroku), change the `Host` header used in health monitor requests. For more details, refer to [Override HTTP Host headers](/load-balancing/additional-options/override-http-host-headers/).

---

## API commands

The Cloudflare API supports the following commands for pools. Examples are given for user-level endpoint but apply to the account-level endpoint as well.

| Command                                                                                                       | Method   | Endpoint                                                   |
| ------------------------------------------------------------------------------------------------------------- | -------- | ---------------------------------------------------------- |
| [Create Pool](/api/resources/load_balancers/subresources/pools/methods/create/)                               | `POST`   | `accounts/:account_id/load_balancers/pools`                |
| [Delete Pool](/api/resources/load_balancers/subresources/pools/methods/delete/)                               | `DELETE` | `accounts/:account_id/load_balancers/pools/:id`            |
| [List Pools](/api/resources/load_balancers/subresources/pools/methods/list/)                                  | `GET`    | `accounts/:account_id/load_balancers/pools`                |
| [Pool Details](/api/resources/load_balancers/subresources/pools/methods/get/)                                 | `GET`    | `accounts/:account_id/load_balancers/pools/:id`            |
| [Pool Health Details](/api/resources/load_balancers/subresources/pools/subresources/health/methods/get/)      | `GET`    | `account/:account_id/load_balancers/pools/:id/health`      |
| [Overwrite specific properties](/api/resources/load_balancers/subresources/pools/methods/edit/)               | `PATCH`  | `accounts/:account_id/load_balancers/pools/:id`            |
| [Overwrite existing pool](/api/resources/load_balancers/subresources/pools/methods/update/)                   | `PUT`    | `accounts/:account_id/load_balancers/pools/:id`            |
| [Preview Pool](/api/resources/load_balancers/subresources/pools/subresources/health/methods/create/)          | `POST`   | `account/:account_id/load_balancers/pools/:id/preview`     |
| [List Pool References](/api/resources/load_balancers/subresources/pools/subresources/references/methods/get/) | `GET`    | `accounts/:account_id/load_balancers/pools/:id/references` |


# Set up Private Network Load Balancing with Cloudflare WAN

Consider the following steps to learn how to configure Private Network Load Balancing solution, using [Cloudflare WAN](/cloudflare-wan/) (formerly Magic WAN) as the on-ramp and off-ramp to securely connect to your private or internal services.

One of the pre-requisites to using Private Network Load Balancing (PNLB) with Cloudflare WAN is having Cloudflare WAN set up in your account and having completed onboarding. You can connect with a Cloudflare One Appliance, or your own hardware via an IPsec or GRE tunnel. Check out the [Cloudflare WAN documentation](/cloudflare-wan/get-started/) for more details or to get started.

## 1. Create Load Balancer Pools

Load Balancer Pools are logical groupings of endpoints — typically organized by physical datacenter or geographic region. The endpoints in the pool are the destinations where traffic is ultimately routed.

:::note
Endpoints accessed via Cloudflare WAN must be accessible in and assigned to the default VNET.
:::

:::caution
The IP destination addresses must also be routable in your Cloudflare WAN configuration. Please contact your Cloudflare account team to confirm that the addresses are available in your configuration.
:::

Pools can be created using either the Cloudflare dashboard or the API. Refer to the [Create a pool](/load-balancing/pools/create-pool/#create-a-pool) documentation section for more information.

## 2. Create an Account Load Balancer with a Private IP

1. Go to **Load Balancing** at the account level and select **Create a Load Balancer**.
2. Select **Private Load Balancer**.
3. On the next step you can choose to associate this load balancer with either:
 - A CGNAT IP from the Cloudflare range or
 - A custom [RFC1918 address](https://datatracker.ietf.org/doc/html/rfc1918).
4. Add a descriptive name to identify your Load Balancer.
5. Proceed through the setup.

After selecting an IP address and completing the setup, you will be redirected to the Load Balancing dashboard. You can locate your load balancer using the search bar or by filtering for **Private** load balancers. Be sure to note the assigned IP address, as it will be required in the following steps.

:::note
Traffic from your load balancer will appear to originate from one of Cloudflare's IP addresses. These IP addresses must be whitelisted to ensure proper traffic flow. Ensure your routing is properly configured to return traffic to your IPsec/GRE tunnels and not the public Internet. Private Load Balancers created with a Cloudflare private IP address will receive a default address in the CGNAT range `100.112.0.0`. This IP address is configurable. Refer to [Cloudflare source IP range](/cloudflare-wan/configuration/how-to/configure-cloudflare-source-ips/) to learn more.
:::

## 3. FQDN override (optional)

If you want your load balancer and its endpoints to be transparently accessible to users via a hostname, you can create a DNS record in your internal DNS system or create an override in Cloudflare that maps the hostname to the Load Balancer's IP address. This ensures that traffic destined for the hostname resolves to the correct IP.

To create the override, follow these steps:

1. In **Gateway**, select **Firewall policies**.
2. In the **DNS** tab, create an override where:
   - The **Selector** equals `Host`
   - The **Operator** equals `is`
   - The **Value** is the hostname you wish to associate with your load balancer.
3. Set the **Action** to _Override_, and in **Override Hostname**, enter the IP address of your Private Load Balancer.

Requests to the hostname will now resolve to your private load balancer.

# Private Network Load Balancing

Private Network Load Balancing enables you to load balance traffic between servers within a data center ([endpoint steering](/load-balancing/understand-basics/traffic-steering/origin-level-steering/)) and between private applications. This helps you eliminate the need for hardware appliances and facilitates the migration of your infrastructure to the cloud, providing advantages such as elastic scalability and enhanced reliability.

Private Network Load Balancing supports not only public IPs but also virtual IPs and private IPs as endpoint values.

---

:::note

This page assumes a certain level of familiarity with how the Cloudflare Load Balancing solution works. For an introductory overview refer to [Load Balancing components](/load-balancing/understand-basics/load-balancing-components/).
:::

---

---

## Off-ramps

Off-ramps create a direct and secure way for Cloudflare to connect into your networks that are not publicly available.

Since traffic steering decisions or failover mechanisms rely on the health information of pools and endpoints, being able to input your virtual or private IPs directly as endpoints within your load balancer means you can better leverage existing health monitoring.

### Tunnel

Currently, to be able to connect to private IP origins, Cloudflare load balancers require a [Cloudflare tunnel](/cloudflare-one/networks/connectors/cloudflare-tunnel/) with an associated [virtual network (VNet)](/cloudflare-one/networks/virtual-networks/). If you are connecting to your endpoints using a [published application route](/cloudflare-one/networks/connectors/cloudflare-tunnel/routing-to-tunnel/public-load-balancers) a VNet is not necessary.

Once the endpoint and virtual network (VNet) tunnel association is configured, Cloudflare can determine not only the tunnel health but also the health of the corresponding virtual or private IP targets.

Refer to [Set up Private Network Load Balancing for Public traffic to Tunnel](/load-balancing/private-network/public-to-tunnel/) for a detailed guide.

:::note
If your application only needs TCP or UDP proxying (not load balancing), you can skip the Load Balancer and attach Spectrum directly to a virtual network. Refer to [Create a Spectrum application using a virtual network](/spectrum/get-started/#create-a-spectrum-application-using-a-virtual-network-origin).
:::

### Cloudflare WAN

Private Network Load Balancing supports off-ramping traffic for Cloudflare WAN (formerly Magic WAN) tunnels, such as GRE, IPSec or CNI tunnels. For more information refer to the [Set up Private Network Load Balancing with Cloudflare WAN](/load-balancing/private-network/cloudflare-wan/).

---

## On-ramps

Private Network Load Balancing on-ramps, on the other hand, refer to secure paths between the end-user request and the Cloudflare network. Cloudflare Load Balancing supports traffic from [CDN](/cache/), [Spectrum](/spectrum/), [Cloudflare One Client](/cloudflare-one/team-and-resources/devices/cloudflare-one-client/) and [Cloudflare WAN](/cloudflare-wan/) and forward that traffic to a load balancer, and then egress to an endpoint behind any off-ramp (CDN/CNI/IPSec/GRE/Tunnel). Your traffic can ingress and egress by any on-ramp/off-ramp combination.

:::note
When using [Spectrum](/spectrum/) as an on-ramp and [Cloudflare WAN](/load-balancing/private-network/#cloudflare-wan) as an off-ramp the [proxy protocol](/spectrum/how-to/enable-proxy-protocol/) setting in Spectrum is not supported.
:::

---

## Use cases

- **Requests originating from the public Internet and directed to a private/internal service**: You can route requests from the Internet to your internal services on internal IPs - such as accounting or production automation systems - using [Cloudflare Tunnel](/cloudflare-one/networks/connectors/cloudflare-tunnel/).

- **Intelligent traffic routing**: Benefit from failover for your private traffic and have the ability to monitor the health of these IP targets directly, rather than load balancing to a tunnel and only monitoring the health of the tunnel itself.

- **Host applications on non-standard ports**: Easily specify and route traffic to applications hosted on private IP addresses using non-standard ports, allowing greater flexibility in service configuration without requiring changes to existing infrastructure.

- **Public and Private Load Balancers**: Public LBs can direct Internet traffic to private IP addresses, supporting all L7 products like WAF and API Shield. Private LBs direct traffic originating from private networks to private IP addresses and require an on-ramp like the Cloudflare One Client or Cloudflare WAN.

# Set up Private Network Load Balancing for Public traffic to Tunnel


Consider the following steps to learn how to configure Private Network Load Balancing solution, using [Cloudflare Tunnel](/cloudflare-one/networks/connectors/cloudflare-tunnel/) as the off-ramp to securely connect to your private or internal services.

## 1. Configure a Cloudflare tunnel with an assigned virtual network

The specific configuration steps can vary depending on your infrastructure and services you are looking to connect. If you are not familiar with Cloudflare Tunnel, the pages linked on each step provide more guidance.

1. [Create a tunnel](/cloudflare-one/networks/connectors/cloudflare-tunnel/get-started/create-remote-tunnel/#1-create-a-tunnel) to connect your data center to Cloudflare.
2. Create a [virtual network](/cloudflare-one/networks/connectors/cloudflare-tunnel/private-net/cloudflared/tunnel-virtual-networks/) and assign it to the tunnel you configured in the previous step.

 

### Dashboard

To create a virtual network:

1. In the [Cloudflare dashboard](https://dash.cloudflare.com/), go to **Zero Trust** > **Settings** > **WARP Client** and find the **Virtual networks** setting.
2. Select **Add new** or **Manage** > **Create virtual network** to create virtual networks.
3. Define your virtual network name and select **Save**.

To assign the virtual network to the tunnel:

1. Go to **Networks** > **Tunnels**.
2. Select the tunnel you created in the previous steps and select **Configure**.
3. Under **Private Network**, select **Add a private network**.
4. Specify an IP range under **CIDR** and select the virtual network under **Additional settings**.
5. Select **Save private network**.

 

### cli

To create a virtual network:

```sh
cloudflared tunnel vnet add <VNET_NAME>
```

To assign the virtual network to the tunnel:

```sh
cloudflared tunnel route ip add --vnet <VNET_NAME> <IP_RANGE> <TUNNEL_NAME>
```

 

## 2. Configure Cloudflare Load Balancing

Once you have Cloudflare tunnels with associated virtual networks (VNets) configured, the VNets can be specified for each endpoint when you [create or edit a pool](/load-balancing/pools/create-pool/#create-a-pool). This will enable Cloudflare load balancers to use the correct tunnel and securely reach the private IP endpoints.

The specific configuration will vary depending on your use case. Refer to the following steps to understand the workflow.

1. [Create the Load Balancing monitor](/load-balancing/monitors/create-monitor/) according to your needs.
2. [Create the pool](/load-balancing/pools/create-pool/) specifying your private IP addresses and corresponding virtual networks.

:::note

- Currently, Cloudflare does not support entering the same endpoint IP addresses more than once, even when using different virtual networks.
- All endpoints with private IPs must have `virtual_network_id` specified.

:::

3. [Create the load balancer](/load-balancing/load-balancers/create-load-balancer/), specifying the pool and monitor you created in the previous steps, as well as the desired [global traffic steering policies](/load-balancing/understand-basics/traffic-steering/steering-policies/) and [custom rules](/load-balancing/additional-options/load-balancing-rules/).

:::caution[Spectrum limitations]

If you will use the load balancer with [Spectrum](/spectrum/), consider the applicable [limitations](/load-balancing/additional-options/spectrum/#limitations) on load balancing and monitoring options.

:::


# Set up Private Network Load Balancing with Client-to-Tunnel


You can use Private Network Load Balancing to distribute Cloudflare One Client traffic to private hostnames and IPs connected via [Cloudflare Tunnel](/cloudflare-one/networks/connectors/cloudflare-tunnel/).

For example, assume you have an internal application running in two data centers, and you want Cloudflare One Client users to access the application from the data center closest to their geographic location. A typical load balancing configuration is shown in the following diagram:

```mermaid
graph LR
    W[WARP clients] --> C{Private load balancer <br> 100.112.0.0}
    C -- Tunnel 1 --> cf1
    C -- Tunnel 2 --> cf2
		subgraph D2[Data center 2]
			cf2@{ shape: processes, label: "cloudflared" }
			subgraph F[Pool 2]
					S3["Endpoint <br> 10.0.0.1 (VNET-2)"]
					S4["Endpoint <br> 10.0.0.2 (VNET-2)"]
			end
			cf2-->S3
			cf2-->S4
		end
		subgraph D1[Data center 1]
			cf1@{ shape: processes, label: "cloudflared" }
			subgraph E[Pool 1]
					S1["Endpoint <br> 10.0.0.1 (VNET-1)"]
					S2["Endpoint <br> 10.0.0.2 (VNET-1)"]
			end
			cf1-->S1
			cf1-->S2
		end

		style E stroke-width:2px,stroke-dasharray: 5 5
		style F stroke-width:2px,stroke-dasharray: 5 5
```

The components in the diagram include:

- **cloudflared**: Each data center is connected to Cloudflare with its own Cloudflare Tunnel. `cloudflared` installs on one or [more](/cloudflare-one/networks/connectors/cloudflare-tunnel/configure-tunnels/tunnel-availability/#cloudflared-replicas) host machines in the network.
- **Private load balancer IP**: End users connect to the application using the load balancer's IP address. This can either be a Cloudflare-assigned IP in `100.112.0.0/16` or a custom `/32` IP in an [RFC 1918 range](https://datatracker.ietf.org/doc/html/rfc1918).
- **Load balancer pool**: The load balancer is configured with one [pool](/load-balancing/understand-basics/load-balancing-components/#pools) per tunnel.
- **Load balancer endpoint**: A pool contains one or more endpoints, where each endpoint is a server behind `cloudflared` that is running the application. If your servers have overlapping IPs, you can assign a distinct [virtual network (VNET)](/cloudflare-one/networks/connectors/cloudflare-tunnel/private-net/cloudflared/tunnel-virtual-networks/) per tunnel so that Load Balancer can deterministically route requests to the correct endpoint.

:::note
Load Balancing does not currently support [private hostname routing](/cloudflare-one/networks/connectors/cloudflare-tunnel/private-net/cloudflared/connect-private-hostname/). Load balancing endpoints must be defined using an IP address and virtual network (for example, `10.0.0.1 (VNET-1)`).
:::

## Prerequisites

- Your endpoint IP addresses route through Cloudflare Tunnel. To learn how to connect your private network, refer to [Connect an IP/CIDR](/cloudflare-one/networks/connectors/cloudflare-tunnel/private-net/cloudflared/connect-cidr/).

## 1. Create load balancer pools

Load balancer pools are logical groupings of endpoints, typically organized by physical datacenter or geographic region. The endpoints in the pool are the destinations where traffic is ultimately routed.

Pools can be created using either the Cloudflare dashboard or the API.

### Dashboard

To create a pool using the dashboard, refer to the [Create a pool](/load-balancing/pools/create-pool/#create-a-pool) documentation.

:::note[Endpoint IP address limitations]

- All endpoints with private IPs must have a [virtual network (VNET)](/cloudflare-one/networks/connectors/cloudflare-tunnel/private-net/cloudflared/tunnel-virtual-networks/) specified. If you did not select a VNET when adding a Cloudflare Tunnel route, the endpoint will be assigned to the `default` VNET.
- A pool cannot have multiple endpoints with the same IP address, even when using different virtual networks. You can assign endpoints with overlapping IPs to different pools, as shown in the [example diagram](#_top).
  :::

### API

To get a list of your current virtual networks, use the [List virtual networks](/api/resources/zero_trust/subresources/networks/subresources/virtual_networks/methods/list/) API operation.

Enable virtual/private IP support by adding the `virtual_network_id` field to the `origins` in your API request. Refer to the [Cloudflare Load Balancer API documentation](/api/resources/load_balancers/subresources/pools/methods/create/) for more information on how to create a pool using the API.

The following example adds a Cloudflare Tunnel endpoint to an existing Load Balancer pool:

`PATCH /accounts/{account_id}/load_balancers/pools/{pool_id}`

## 2. Create a private load balancer

1. In the Cloudflare dashboard, go to the **Load Balancing** page.

   

https://dash.cloudflare.com/?to=/:account/load-balancing

2. Select **Create a Load Balancer**.
3. Select **Private Load Balancer**.
4. On the next step you can choose to associate this load balancer with either:
   - A Cloudflare-assigned IP from the `100.112.0.0/16` range
   - A custom `/32` IP in an [RFC 1918 range](https://datatracker.ietf.org/doc/html/rfc1918)
5. Add a descriptive name to identify your load balancer.
6. Proceed through the setup.

After completing the setup, you will be redirected to the Load Balancing dashboard. You can locate your load balancer using the search bar or by filtering for **Private** load balancers. Be sure to note the load balancer IP as it will be required in the following steps.

## 3. Route the load balancer IP through the Cloudflare One Client

In order for Cloudflare One Clients to connect to your load balancer, the load balancer's IP address must route through the WARP tunnel in your [Split Tunnel settings](/cloudflare-one/team-and-resources/devices/cloudflare-one-client/configure/route-traffic/split-tunnels/).

1. In the [Cloudflare dashboard](https://dash.cloudflare.com/), go to **Zero Trust** > **Team & Resources** > **Device profiles**.
2. Find the [device profile](/cloudflare-one/team-and-resources/devices/cloudflare-one-client/configure/device-profiles/) you would like to modify and select **Edit**.
3. Under **Split Tunnels**, check whether your [Split Tunnels mode](/cloudflare-one/team-and-resources/devices/cloudflare-one-client/configure/route-traffic/split-tunnels/#change-split-tunnels-mode) is set to **Exclude** or **Include**.
4. Select **Manage**. Depending on the mode:
   - **Exclude mode**: Delete the IP range that contains your load balancer IP. For example, if your load balancer has a Cloudflare-assigned CGNAT IP, delete `100.64.0.0/10`. We recommend [adding back the IPs](/cloudflare-one/networks/connectors/cloudflare-tunnel/private-net/cloudflared/connect-cidr/#3-route-private-network-ips-through-the-cloudflare-one-client) that are not being used by your load balancer.
     :::note
     Some IPs in the `100.64.0.0/10` range may be reserved for other Zero Trust services such as WARP CGNAT IPs, or Gateway initial resolved IPs if your account uses a legacy or custom range within CGNAT space. These IPs should remain deleted from the Exclude list.
     :::
   - **Include mode**: Add your load balancer IP.

Cloudflare One Client traffic can now reach your private load balancer. For example, if your load balancer points to a web application, you can test by running `curl <load-balancer-IP>` from the device. This traffic will be distributed over Cloudflare Tunnel to your private endpoints according to your configured steering method.

## 4. (Optional) Assign a hostname to the load balancer

If you want your load balancer and its endpoints to be transparently accessible to users via a hostname, you can create a Gateway DNS [Override policy](/cloudflare-one/traffic-controls/dns-policies/#override) that maps the hostname to the load balancer's IP address. This ensures that traffic destined for the hostname resolves to the correct IP.

1. In the [Cloudflare dashboard](https://dash.cloudflare.com/), go to **Zero Trust** > **Traffic policies** > **Firewall policies** > **DNS**.
2. Select **Add a policy**.
3. In **Traffic**, create an expression where the **Selector** equals `Host`, the **Operator** equals `is`, and **Value** is the hostname you wish to associate with your load balancer. For example,

   | Selector | Operator | Value                |
   | -------- | -------- | -------------------- |
   | Host     | is       | `app.internal.local` |

4. Set the **Action** to _Override_.
5. In **Override Hostname**, enter your private load balancer IP (for example, `100.112.0.0`).

Requests to the hostname will now resolve to your private load balancer.


# Reference

See the following pages for more information about Cloudflare Load Balancing:


# Limitations

Name | Non-Enterprise | Enterprise |
 --- | --- | --- |
 Load balancers | 20 | custom |
 Monitor intervals | 15s (min), 3600s (max) | 10s (min), 3600s (max) |
 Monitors | 1.5x the number of pools | 1.5x the number of pools |
 Endpoints | 20 | custom |
 Pools | 20 | custom |

# Analytics


Using load balancing analytics, you can:

- Evaluate traffic flow.
- Assess the health status of endpoints in your pools.
- Review changes in pools and pool health over time.

:::note

Load balancing analytics are only available to customers on paid plans (Pro, Business, and Enterprise).

:::

## Dashboard Analytics

### Overview metrics

To view **Overview** metrics for your load balancer, go to **Traffic** > **Load Balancing Analytics**.

These metrics show the number of requests routed to specific pools within a load balancer, helping you:

- Evaluate the effects of adding or removing a pool.
- Decide when to create new pools.
- Plan for peak traffic demands and future infrastructure needs.

Add additional filters for specific pools, times, regions, and endpoints.

:::note

Load balancing <strong>requests</strong> are the number of uncached requests made by your load balancer. By default, Cloudflare caches resolved IP addresses for up to five seconds.

:::

### Latency

**Latency** metrics show an interactive map, helping you identify regions with **Unhealthy** or **Slow** pools.

To view latency information for your load balancer, go to **Traffic** > **Load Balancing Analytics** > **Latency**.

### Logs

**Logs** provide a history of all endpoint status changes and how they affect your load balancing pools. Load Balancing only logs events that represent a status change for an endpoint, from healthy to unhealthy or vice versa.

When a Monitor Group is attached to a pool, each logged health event includes the `monitors` field.
This field lists the individual monitors within the group and their results, making it easier to see which monitor contributed to a status change.

Example event (truncated):

```json
{
	"id": <id>,
	"timestamp": "2025-09-22 19:22:00",
	"pool": {
		"id": "<id>",
		"name": "example-monitor-group-test-pool-us",
		"healthy": true,
		"changed": false,
		"minimum_origins": 1
	},
	"origins": [
		{
			"name": "origin-a",
			"ip": "192.0.2.10",
			"enabled": true,
			"healthy": true,
			"failure_reason": "No failures",
			"response_code": 200,
			"monitors": [
				{
					"id": "<id>",
					"healthy": true,
					"failure_reason": "No failures",
					"response_code": 200,
					"must_be_healthy": true,
					"monitoring_only": false
				},
				{
					"id": "<id>",
					"healthy": true,
					"failure_reason": "No failures",
					"response_code": 200,
					"must_be_healthy": true,
					"monitoring_only": false
				},
				{
					"id": "<id>",
					"healthy": false,
					"failure_reason": "HTTP timeout occurred",
					"must_be_healthy": false,
					"monitoring_only": true
				}
			]
		},
		{
			"name": "origin-b",
			"ip": "198.51.100.25",
			"enabled": true,
			"healthy": false,
			"failure_reason": "TCP connection failed",
			"changed": true,
			"monitors": [
				{
					"id": "<id>",
					"healthy": false,
					"failure_reason": "TCP connection failed",
					"must_be_healthy": true,
					"monitoring_only": false
				},
				{
					"id": "<id>",
					"healthy": true,
					"failure_reason": "No failures",
					"response_code": 200,
					"must_be_healthy": true,
					"monitoring_only": false
				},
				{
					"id": "<id>",
					"healthy": false,
					"failure_reason": "HTTP timeout occurred",
					"must_be_healthy": false,
					"monitoring_only": true
				}
			]
		}
	]
}
```

In this example:

- Each origin includes a `monitors` array listing all monitors within the attached group.
- Fields such as `must_be_healthy` `and monitoring_only` indicate each monitor's role in determining the origin's overall health.
- The `healthy` and `failure_reason` fields show which individual monitor checks succeeded or failed.

To access logs in the dashboard, go to **Traffic** > **Load Balancing Analytics**.

## GraphQL Analytics

For more flexibility, get load balancing metrics directly from the [GraphQL Analytics API](/analytics/graphql-api/).

Get started with a sample query:

**Requests per pool**

This query shows the number of requests each pool receives from each location in Cloudflare's global network.

```graphql graphql-api-explorer title="Query"
query RequestsPerPool($zoneTag: string, $start: Time, $end: Time) {
	viewer {
		zones(filter: { zoneTag: $zoneTag }) {
			loadBalancingRequestsAdaptiveGroups(
				limit: 100
				filter: {
					datetime_geq: $start
					datetime_leq: $end
					lbName: "lb.example.com"
				}
				orderBy: [datetimeFifteenMinutes_DESC]
			) {
				count
				dimensions {
					datetimeFifteenMinutes
					coloCode
					selectedPoolName
				}
			}
		}
	}
}
```

```json title="Response (truncated)"
{
    "data": {
        "viewer": {
            "zones": [
                {
                    "loadBalancingRequestsAdaptiveGroups": [
                        {
                            "count": 4,
                            "dimensions": {
                                "coloCode": "IAD",
                                "datetimeFifteenMinutes": "2021-06-26T00:45:00Z",
                                "selectedPoolName": "us-east"
                            }
                        },
                        ...
                    ]
                }
            ]
        }
    }
}
```


**Requests per data center**

This query shows the weighted, round-trip time (RTT) measurement (`avgRttMs`) for monitor requests from a specific data center (for example, Singapore or `SIN`) to each pool in a specific load balancer.

:::caution

Note that `avgRttMs` refers to the round-trip time that is measured by the monitors and used in steering decisions. `avgRttMs` is different from the raw RTT for individual requests that reach the Cloudflare network.
:::

```graphql graphql-api-explorer title="Query"
query RequestsPerDataCenter($zoneTag: string, $start: Time, $end: Time) {
	viewer {
		zones(filter: { zoneTag: $zoneTag }) {
			loadBalancingRequestsAdaptive(
				limit: 100
				filter: {
					datetime_geq: $start
					datetime_leq: $end
					lbName: "lb.example.com"
					coloCode: "SIN"
				}
				orderBy: [datetime_DESC]
			) {
				selectedPoolName
				pools {
					poolName
					healthy
					healthCheckEnabled
					avgRttMs
				}
			}
		}
	}
}
```

```json title="Response (truncated)"
{
    "data": {
        "viewer": {
            "zones": [
                {
                    "loadBalancingRequestsAdaptive": [
                        {
                            "pools": [
                                {
                                    "avgRttMs": 67,
                                    "healthCheckEnabled": 1,
                                    "healthy": 1,
                                    "poolName": "asia-ne"
                                },
                                {
                                    "avgRttMs": 156,
                                    "healthCheckEnabled": 1,
                                    "healthy": 1,
                                    "poolName": "us-east_and_asia-ne"
                                },
                                {
                                    "avgRttMs": 237,
                                    "healthCheckEnabled": 1,
                                    "healthy": 1,
                                    "poolName": "us-east"
                                },
                            ],
                            "selectedPoolName": "asia-ne"
                        },
                    ...
                    ]
                }
            ]
        }
    }
}
```


# Regions API


Cloudflare’s Load Balancing Regions API has several uses:

- Identify which countries/areas (states/provinces in the case of the U.S. and Canada) are part of a specific Cloudflare Load Balancer region.
- Identify the Cloudflare Load Balancer region for a particular country/area (states/provinces in the case of the U.S. and Canada).

The Region API uses 2-letter [ISO-3166-1 alpha-2 codes](https://www.iso.org/iso-3166-country-codes.html) for countries/areas and, in the case of the U.S. and Canada, ISO-3166-2 subdivision codes for states/provinces. Only the U.S. and Canada are provided with these subdivisions.

There are two main optional parameters for the Region API:

- country_code is a string containing a two-letter alpha-2 country code per ISO 3166-1. For example: /load_balancers/regions?country_code=US
- subdivision_code is a string containing a two-letter subdivision code for the U.S. and Canada per ISO 3166-2. For example: /load_balancers/regions?subdivision_code=CA

For additional details and examples on using the Region Mapping API, see [Cloudflare’s API documentation](/api/resources/load_balancers/subresources/regions/methods/list/).

## List of Load Balancer regions


# Health monitor notifications

Cloudflare is migrating the notifications used by load balancing [health monitors](/load-balancing/monitors/) to use Cloudflare's centralized [Notifications Service](/notifications/).

## What is changing and why?

Cloudflare’s account-level [Notifications Service](/notifications/) is now the centralized location for most Cloudflare services. This change promotes consistency and streamlined administration, as well as gives you more options for notification delivery such as configuring webhooks or associating multiple pools with the same notification. These new notifications will also be managed at the account level instead of the zone level.

We strongly encourage all customers to migrate existing Health Monitor notifications to Cloudflare’s centralized Notifications Service to avoid lapses in alerts.

## Migration guide

You should use this guide to migrate over **all** your existing health monitor notifications.

### Step 1 - Find existing notifications

First you should determine which pools are using notifications. It's often easier if you use the Cloudflare API to list all your pools and look for the `notification_email` parameter.

**With code**

Use the [Cloudflare API](/api/resources/load_balancers/subresources/pools/methods/list/) to list all your pools and then look for whether each pool has a value for the `notification_email` parameter.

```bash title="Request"
curl "https://api.cloudflare.com/client/v4/accounts/{account_id}/load_balancers/pools" \
--header "Authorization: Bearer <API_TOKEN>" \
| jq '[.result[] | select(.notification_email != "") | {name, notification_email}]'
```

```json title="Response"
[
    {
        "name": "pool-1",
        "notification_email": "user@example.com"
    },
    {
        "name": "pool-2",
        "notification_email": "user@example.com"
    },
    {
        "name": "pool-3",
        "notification_email": "user@example.com"
    },
    {
        "name": "pool-4",
        "notification_email": "user@example.com"
    }
]
```


**No code**

To find pools with existing notifications in the dashboard:

1. Log into the [Cloudflare dashboard](https://dash.cloudflare.com) and select your account and domain.
2. Go to **Load Balancing**.
3. Select the **Pools** tab.
4. On a pool, select **Edit**.
5. For **Health Check Notifications**, check the value is toggled to **On** and an email address is present in the **Notification email address** field.

### Step 2 - Create new notifications

In this step, you should create new notifications to replace all of your existing legacy notifications.

**With code**

If using the Cloudflare API, [re-create all your existing notifications](/api/resources/alerting/subresources/policies/methods/create/) with the following parameters specified:

```json
"alert_type": "load_balancing_health_alert",
"filters": {
    "pool_id": <<ARRAY_OF_INCLUDED_POOL_IDS>>,
    "new_health": <<ARRAY_OF_STATUS_TRIGGERS>> ["Unhealthy", "Healthy"],
    "event_source": <<ARRAY_OF_OBJECTS_WATCHED>> ["pool", "origin"]
}
```


**No code**

On the pool you located in [Step 1](#step-1---find-existing-notifications), look for **Pool Notifications**. Select **Create a Health Alert** to start [creating a notification](/notifications/get-started/#create-an-alert).

### Step 3 - Remove deprecated notifications

As the final step in the migration process, you need to remove all emails from your legacy notifications to ensure that you no longer receive deprecation emails moving forward.

Though you can perform these steps in the dashboard, Cloudflare recommends you use our new API endpoint for added convenience.

**With code**

If using the Cloudflare API, we recently added a [`PATCH`](/api/resources/load_balancers/subresources/pools/methods/bulk_edit/) endpoint so you can easily remove email notifications from multiple pools at the same time.

`PATCH /accounts/{account_id}/load_balancers/pools`

This API call supports the standard pagination query parameters, either `limit/offset` or `per_page/page`, so by default it only updates the first 25 pools listed. To make sure you update all your pools, you may want to adjust your API call so it loops through various pages or includes a larger number of pools with each request.

If needed, you can remove legacy notifications by using the dashboard.

**No code**

Once you created your new notification in [Step 2](#step-2---create-new-notifications), you will return to the pool you were editing previously. To disable the deprecated notifications, you must remove all notification email addresses from the field.

If you do not complete this step (removing all notification emails from all pools), your migration will not be considered complete and you will continue to receive additional emails about this deprecation.


# Migration guides




# Migrate to new GraphQL nodes

After 30 September 2021, Cloudflare will make the following changes to the Load Balancing GraphQL schema:

* Deprecate nodes:
  * `loadBalancingRequestsGroups` will be deprecated for `loadBalancingRequestsAdaptiveGroups`
  * `loadBalancingRequests` will be deprecated for `loadBalancingRequestsAdaptive`
* Deprecate the `date` field (replace it with the existing `datetime` field)
* Add the `sampleInterval` field

## Example query

The following example:

* Replaces `loadBalancingRequestsGroups` with `loadBalancingRequestsAdaptiveGroups`
* Replaces `date` with `datetime`
* Uses the new `sampleInterval` field

```json
query {
  viewer {
    zones(filter: { zoneTag: "your Zone ID" }) {
      loadBalancingRequestsAdaptiveGroups(
        filter: {
          datetime_gt: "2021-06-12T04:00:00Z",
          datetime_lt: "2021-06-13T06:00:00Z"
        }
      ) {
        dimensions {
          datetime
          coloCode
          ...
        }
        avg {
          sampleInterval
        }
      }
    }
  }
}
```

# Common error codes

The Cloudflare Load Balancing API adds global health to each pool and endpoint. It also gives you a view into what our network sees at a wider level. Cloudflare uses a quorum system to determine pool and endpoint health status. The quorum is taken from PoPs responsible for running health monitor requests in a region, and the majority result is used.

When troubleshooting failures, use the Cloudflare API for programmatic access to Cloudflare Load Balancing. The Health Monitor Events and Load Balancer Monitors routes are excellent tools for accessing load balancing event logs and reconfiguring Cloudflare monitors.

You can get a per-data center breakdown of the health of your endpoints from the Cloudflare API from the List Health Monitor Events command:

```txt
GET user/load_balancing_analytics/events
```

If a health monitor request fails, the breakdown will include the reason.

Common troubleshooting causes and solutions are listed below.

***

## TCP connection failed

### Cause

Our health monitor requests failed to establish a TCP connection to your endpoint.

### Solution

This typically occurs when there is a network failure between Cloudflare and your endpoint, and/or a firewall refused to allow our connection. Ensure your network and firewall configurations are not interfering with load balancing traffic.

***

## HTTP timeout occurred

### Cause

The endpoint failed to return an HTTP response within the timeout configured. This happens if you have the timeout set to a low number — 1 or 2 seconds, for instance.

### Solution

We recommend increasing the HTTP response timeout to allow the endpoint to respond.

***

## Response code mismatch error

### Cause

Cloudflare receives an HTTP status code that does not match the values defined in the `expected_codes` property of your Cloudflare monitor configuration.

### Solution

Response codes must match the `expected_codes`. Use the List Monitors API command to confirm the values are correct.

### Alternate cause

You may also see this issue if you have a monitor configured to use HTTP connections and your endpoint is redirecting to HTTPS. In this case, the response code will often be 301, 302, or 303.

### Solution

Either change your Cloudflare monitor configuration to use HTTPS, or set the value of `follow_redirect` to `true` so that we can resolve the correct status code.

***

## Response body mismatch error

### Cause

The response body returns from your endpoint and does not include the (case-insensitive) value of `expected_body` configured in your monitor.

Note that we only read the first 10 KB of the response. If you return a larger response, and the expected\_body is not in the first 10 KB, the health monitor request will fail.

### Solution

Ensure the expected\_body is in the first 10 KB of the response body.

***

## TLS untrusted certificate error

### Cause

The certificate is not trusted by a public Certificate Authority (CA).

### Solution

If you're using a self-signed certificate, we recommend either using a publicly trusted certificate or setting the `allow_insecure` property on your monitor to `true`.

***

## TLS name mismatch error

### Cause

Our health monitor (client) was not able to match a name on the server certificate to the hostname of the request.

### Solution

Use the List Monitors command to confirm that the `header` value set in the Cloudflare monitor is correct and the Update Monitors command to make any necessary changes.

***

## TLS protocol error

### Cause

This error can occur if you’re using an older version of TLS or your endpoint is not configured for HTTPS.

### Solution

Ensure that your endpoint supports TLS 1.0 or greater and is configured for HTTPS.

***

## TLS unrecognized name error

### Cause

The server did not recognize the name provided by the client. When a host header is set, we set this as the ServerName in the initial TLS handshake. If not set, we will not provide a ServerName, which can cause this error.

### Solution

Set the host header in your monitor object.

***

## No route to host error

### Cause

The IP address cannot be reached from our network. Common causes are ISP or hosting provider network issues (e.g. BGP level), or that the IP does not exist.

### Solution

Make sure IP is accurate, and if it is check if there is an ISP or hosting provider network issue.

***

## Exceeded quota error

### Cause

You will receive this error if you attempt to create more objects (monitors, pools, or endpoints) than are included in your plan.

If using the dashboard, you will not be able to create additional objects.

If you're using the **Cloudflare API**, you will receive an error message.

### Solution

* Enterprise customers who need to create more objects (load balancers, pools, endpoints, or monitors) should reach out to their account team to discuss this issue.
* Self-service customers can upgrade their Load Balancing subscription with more endpoints to increase load balancing capacity.

***

## TCP Timeout

### Cause

Data transmission was not acknowledged and retransmit of data did not succeed.

### Solution

Confirm whether the SYN-ACK for the handshake takes place at your endpoint and [contact Cloudflare Support](/support/contacting-cloudflare-support/).

***

## TLS Handshake Failure

### Cause

Indicates that the browser's connection to the web server is not secure.

### Solution

Change wifi networks, connect to a wired network, or verify the network connection is stable.

***

## Network Unreachable

### Cause

Cloudflare cannot connect to the endpoint due to network unavailability. This is usually caused by a network issue or incorrect IP.

### Solution

Check either the IP entered for the endpoint in Cloudflare's Load Balancer configuration or the IP returned via DNS for the endpoint hostname.

***

## HTTP Invalid Response

### Cause

Usually caused by an HTTP 502 error or bad gateway.

### Solution

Ensure the endpoint responds to requests and that no applications have crashed or are under high load.

***

## DNS Unknown Host

### Cause

The endpoint hostname does not exist.

### Solution

Confirm the endpoint resolves to an IP address.

***

## Connection Reset by Peer

### Cause

A network error occurred while the client received data from the endpoint.

### Solution

Confirm whether the endpoint is experiencing a high amount of traffic or an error.

***

## Monitor Config Error

### Cause

There was a configuration error in the monitor and no checks are run against the pool endpoints.

### Solution

Review your monitor configuration to ensure it matches an expected request to your endpoint.

***

## DNS Internal

### Cause

The endpoint's hostname resolves to an internal or orange-clouded IP address. No checks are run against the pool endpoints.

### Solution

Cloudflare does not allow use of an endpoint hostname that is proxied by Cloudflare.

***

## Load Balancing Not Enabled

### Cause

Load Balancing is not enabled for your account or zone.

### Solution

For Enterprise customers, reach out to your Cloudflare Account Team. Free, Pro, and Business customers should [Enable Load Balancing](/load-balancing/get-started/enable-load-balancing/).

***

## Validation failed error

### Cause

You will receive an error if you try to set the host header value while configuring a load balancer endpoint.

### Solution

Cloudflare now restricts configured [endpoint host headers](/load-balancing/additional-options/override-http-host-headers/) to fully qualified domain names (FQDNs) that are immediate subdomains of a zone associated with the account. For example, this host header would be the same zone as the load balancer itself, but pools may be used across multiple Load balancers.

***

## Object referenced by other objects

### Cause

You will receive this error when you attempt to delete a pool that is referenced by a load balancer [geo steering](/load-balancing/understand-basics/traffic-steering/steering-policies/geo-steering/) region, or by a [pool set](/load-balancing/understand-basics/traffic-steering/pool-sets/).

### Solution

For a geo steering reference, remove the pool from the load balancer's geo steering configuration. If your load balancer no longer uses geo steering, you will need to [re-enable geo steering](/load-balancing/understand-basics/traffic-steering/steering-policies/geo-steering/) and then remove the pool.

For a pool set reference, remove the pool from every pool set that references it, including any `overrides.pool_weights` and `overrides.fallback_pool` entries.

***

## Other Failure

### Cause

If the failure cannot be classified as any other type of failure mentioned above.

### Solution

[Contact Cloudflare Support](/support/contacting-cloudflare-support/).

# Troubleshooting

For more guidance related to common issues with load balancers, refer to the following resources:


# FAQs

For more detailed information about Load Balancing — including how-to guides, tutorials, and other reference information — check out our [product documentation](/load-balancing/).

:::note

Are you trying to turn on Load Balancing? [Enable Load
Balancing](https://dash.cloudflare.com/?to=/:account/:zone/traffic/load-balancing).
:::

***

## Why is my origin receiving so many health monitor requests?

This issue may be caused by a combination of two issues.

### Multiple Health Monitor Regions

When you [attach a monitor to a pool](/load-balancing/monitors/create-monitor/#create-a-monitor), you can specify the **Health Monitor Regions** that Cloudflare uses to monitor your endpoint health.

If you select multiple regions or choose **All Data Centers (Enterprise Only)**, you may [dramatically increase traffic](/load-balancing/understand-basics/health-details/#how-an-endpoint-becomes-unhealthy) to that pool and its associated endpoints. Each region sends individual health monitor requests from 3 data centers. Using **All Data Centers** sends individual health monitor requests from all existing Cloudflare data centers (and that number of data centers is growing all the time).

To reduce traffic, reduce the number of selected regions or choose an option besides **All Data Centers**.

### Low intervals for health monitor requests

If you have a low interval for your health monitor requests, you may increase the traffic sent to your endpoints.

***

## Why is my endpoint or pool considered unhealthy?

To learn more about how endpoints and pools become unhealthy, refer to [Endpoint and pool health](/load-balancing/understand-basics/health-details).

If you know that your endpoint is healthy but load balancing is reporting it as unhealthy, check the following settings on the [monitor](/load-balancing/monitors):

* Perform a `curl` request against the configured endpoint. Make sure the response you are seeing matches your settings for the monitor.
* Ensure your firewall or web server does not block or rate limit [our health monitors](/fundamentals/reference/cloudflare-site-crawling/#specific-products) and accepts requests from [Cloudflare IP addresses](/fundamentals/concepts/cloudflare-ip-addresses/).
* If you are looking for a specific value in the **Response Body**, make sure that value is relatively static and within the first 10 KB of the HTML page.
* If your endpoint responds with a `301` or `302` status code, make sure **Follow Redirects** is selected.
* Try increasing the **Timeout** value.
* Review the **Host Header** for the health monitor.
* If you are using [Authenticated Origin Pulls (mTLS)](/ssl/origin-configuration/authenticated-origin-pull/), [Origin CA (mTLS)](/ssl/origin-configuration/origin-ca/), [Argo Smart Routing](/argo-smart-routing/), [Dedicated CDN Egress IPs](/smart-shield/configuration/dedicated-egress-ips/), or require [HTTP/2 to Origin](/speed/optimization/protocol/http2-to-origin/), make sure that you entered a zone value for **Simulate Zone** corresponding to the zone with these features configured.

***

## Why does my load balancer route traffic to a secondary pool when the primary pool is still healthy?

You occasionally might see traffic routed away from a pool if a health monitor request fails from a specific data center (even if the endpoint is still healthy). That data center may direct a small number of requests to another pool that is considered healthy by that data center.

To learn more about how endpoints and pools become unhealthy, refer to [Endpoint and pool health](/load-balancing/understand-basics/health-details).

***

## What happens when a pool or endpoint becomes unhealthy?

When a pool or endpoint becomes unhealthy, traffic may be rerouted to other healthy pools or endpoints based on your configuration. You might experience this behavior when using:

1 - Pools with **All-Datacenters** monitoring and the monitor fails in a specific data center. In this case, all traffic will be steered away from impacted endpoints in that datacenter until the monitor succeeds again. These instances are reflected in LB request analytics as steering away from an unhealthy endpoint or pool.

2 - Pools with FQDN endpoint addresses and the recursive DNS lookup fails in a specific data center. In this case, only requests for which the DNS request fails will be steered away from impacted endpoints. This could be sporadic, especially if upstream authoritative resolvers occasionally time out or fail, when the local DNS cache TTL expires and a remote lookup is required in the hot path. This also appears in LB request analytics as steering away from an unhealthy endpoint, and the resolved endpoint IP will be missing from the request log.

To avoid these scenarios:

1 - Do not use **All-Datacenters** monitoring.

2 - Use IP addresses for endpoint configurations. If that is not feasible, use domains for which Cloudflare is authoritative (primary or secondary).

To learn more about how endpoints and pools become unhealthy, refer to [Endpoint and pool health](/load-balancing/understand-basics/health-details).

***

## What is the difference between Load Balancing and Health Checks?

[Cloudflare Load Balancing](/load-balancing/) helps monitor endpoints health and — based on that and other information — route incoming requests accordingly. Individual endpoints have monitors attached, which issue monitor requests at regular intervals.

[Cloudflare Health Checks](/health-checks/) are identical to monitors within a load balancer, but only meant for probing server health (and not distributing traffic).

***

## Why do I see different numbers of requests in Load Balancing Analytics?

You may see different numbers of requests when reviewing [Load Balancing Analytics](/load-balancing/reference/load-balancing-analytics/), especially when compared to other Cloudflare dashboards (Caching, etc.).

Load balancing **requests** are the number of uncached requests made by your load balancer. By default, Cloudflare caches resolved IP addresses for up to five seconds. This built-in caching is often the cause of an discrepancies.

***

## I'm seeing a specific error code for my load balancer or monitor.

For a list of specific error codes and next steps, refer to [Load Balancing Troubleshooting](/load-balancing/troubleshooting).

***

## Related resources

* [Endpoint and pool health](/load-balancing/understand-basics/health-details)
* [Monitors](/load-balancing/monitors)
* [Load Balancing Analytics](/load-balancing/reference/load-balancing-analytics/)

# Adaptive routing

Adaptive routing controls features that modify the routing of requests to pools and endpoints in response to dynamic conditions, such as during the interval between active health monitoring requests. 

## Failover across pools

When there are no healthy endpoints in the same pool, failover across pools extend the zero-downtime failover of requests to healthy endpoints in alternate pools according to the failover order defined by traffic and endpoint steering.

:::caution[Geo-steering limitation]
When using [geo-steering](/load-balancing/understand-basics/traffic-steering/steering-policies/geo-steering/), failover across pools only considers pools within the same geographic grouping. If your NA pool becomes unhealthy, traffic will **not** automatically fail over to your EU pool — it will go to the global fallback pool instead.

To enable cross-region failover, include the desired fallback pool as an additional pool within each region's pool list.

Alternatively, [pool sets](/load-balancing/understand-basics/traffic-steering/pool-sets/) accept a fallback pool for each location, so traffic that exhausts the pools for one location fails over to a pool you choose for that location instead of the global fallback pool.
:::

### Enable failover across pools

1. In the Cloudflare dashboard, go to the **Load Balancing** page.

   

https://dash.cloudflare.com/?to=/:account/load-balancing

2. Navigate to your Load Balancers and select **Edit**.
3. From **Adaptive Routing**, enable **Failover across pools**.

## HTTP/2 GOAWAY handling

When an origin sends a GOAWAY frame, Cloudflare stops sending new requests on that connection but does not mark the endpoint as unhealthy. Safe-to-retry requests (typically GET) are automatically retried on a new connection. Non-idempotent requests (such as POST or PUT) may not be retried unless the request was not yet sent on the closing connection.


# How endpoints and pools become unhealthy


When we talk about dynamic load balancing, that means your load balancer only directs requests to endpoints that can handle the traffic.

But how does your load balancer _know_ which endpoints can handle the traffic? We determine that through a system of monitors, health monitors, and pools.

---

## Dynamic load balancing

Dynamic load balancing happens through a combination of pools, monitors, and health checks.

---

## How an endpoint becomes unhealthy

:::note

If **Health Monitor Regions** for a pool is set to **All Data Centers (Enterprise)**, pool health is determined by a majority of data centers.

:::

Load balancing analytics and logs will only show global health changes.

For greater accuracy and consistency when changing endpoint health status, you can also set the `consecutive_up` and `consecutive_down` parameters via the [Create Monitor API endpoint](/api/resources/load_balancers/subresources/monitors/methods/create/). To change from healthy to unhealthy, an endpoint will have to be marked healthy a consecutive number of times (specified by `consecutive_down`). The same applies — from unhealthy to healthy — for `consecutive_up`.

---

## How a pool becomes unhealthy

When an [individual endpoint becomes unhealthy](#how-an-endpoint-becomes-unhealthy), that may affect the health status of any associated pools (visible in the dashboard):

- **Healthy**: All endpoints are healthy.
- **Degraded**: At least one endpoint is unhealthy, but the pool is still considered healthy and could be receiving traffic.
- **Critical**: The pool has fallen below the number of available endpoints specified in its **Health Threshold** and will not receive traffic from your load balancer (unless other pools are also unhealthy and this pool is marked as the [**Fallback Pool**](#fallback-pools)).
- **Health unknown**: There are either no monitors attached to pool endpoints or the monitors have not yet determined endpoint health.
- **No health**: Reserved for your load balancer's [**Fallback Pool**](#fallback-pools).

:::note

1. When no monitor is attached to a pool, the health status is not considered during steering.
2. Origins are considered down when monitoring is enabled, but the health status is still unknown.
3. If there are no monitors, a fallback pool is still required, but it will only be used if all the default pools have origins with FQDN addresses that cannot be resolved.

:::

### Traffic distribution

### Fallback pools

---

## How a load balancer becomes unhealthy

When one or more pools become unhealthy, your load balancer might also show a different status in the dashboard:

- **Healthy**: All pools are healthy.
- **Degraded**: At least one pool is unhealthy, but traffic is not yet going to the [Fallback Pool](#fallback-pools).
- **Critical**: All pools are unhealthy and traffic is going to the [Fallback Pool](#fallback-pools).

If a load balancer reaches **Critical** health and the pool serving as your fallback pool is also disabled:

- If Cloudflare proxies your hostname, you will see a 530 HTTP/1016 Origin DNS failure.
- If Cloudflare does not proxy your hostname, you will see the SOA record.


# Concepts

Review the following topics to learn more about the basic concepts and components involved in Cloudflare Load Balancing.


# Load Balancing components


This page provides a simplified overview of the three main components of the Cloudflare Load Balancing solution and how they relate to one another.

## Load balancers

For a hostname (`blog.example.com`) to resolve, the Domain Name System (DNS) must return an IP address, where the website or application is hosted (origin).

When you set up a public load balancer, Cloudflare automatically creates an [LB DNS record](/load-balancing/load-balancers/dns-records/) for the specified hostname. This means that, according to a [priority order](/load-balancing/load-balancers/dns-records/#priority-order), instead of simply returning an IP address, the logic you introduced using the Cloudflare Load Balancing solution will be considered.

Note that you can use the root domain as a Load Balancer hostname. When doing so, make sure you enter the hostname without including the auto-generated dot that typically precedes your zone's name.

:::note
Private load balancers are not automatically associated with a hostname. Private load balancers are created with either a CGNAT IP address or a custom RFC-1918 IP address.
:::

## Pools

Within Cloudflare, pools represent your endpoints and how they are organized. As such, a pool can be a group of several endpoints, or you could also have only one endpoint per pool — it depends on what best suits your use case.

For example, if you are only using Cloudflare to globally distribute traffic across regions ([global traffic steering](/load-balancing/understand-basics/traffic-steering/steering-policies/)), each pool could represent one region and, within each region, you could have one endpoint that represents the entry point to your data center.

Cloudflare [Private Network Load Balancing](/load-balancing/private-network/) solution and [endpoint steering](/load-balancing/understand-basics/traffic-steering/origin-level-steering/) capabilities enable you to also load balance traffic between your servers within a data center. In this use case, each pool would represent a data center and contain several endpoints that represent your servers.

:::note[Smart Tiered Cache interaction]
While Smart Tiered Cache selects one Upper Tier per origin, when using Load Balancing, Smart Tiered Cache will select the single best Upper Tier for the entire Load Balancing Pool.
:::

## Endpoints

## Monitors

Finally, monitors are the component you can use to guarantee only [healthy pools](/load-balancing/understand-basics/health-details/) are considered for traffic distribution.

When you configure a monitor and attach it to endpoints, the monitor will issue health monitor requests to your endpoints at regular intervals. This process makes it possible for your load balancer to intelligently handle traffic, considering which endpoints are actually available.

:::note

Health monitors associated with load balancers are different from [**Standalone health checks**](/health-checks/).

:::


# Proxy status


You can load balance your traffic at different levels of the networking stack, such as:

- [Layer 7 (HTTP/HTTPS)](#layer-7-load-balancing) (most common)
- [DNS-only](#dns-only-load-balancing)
- [Layer 4 (TCP)](#layer-4-load-balancing)

---

## Layer 7 load balancing

### Benefits

---

## DNS-only load balancing

### Benefits

 <br />

### Limitations

---

## Layer 4 load balancing


# Regional health


By default, Cloudflare Load Balancing makes one global health decision for each pool and its endpoints. Your load balancer steers on that single decision everywhere.

Regional health changes that. Each region gets its own health decision, with global health as a fallback. A region that cannot reach a pool steers around it right away. It does not wait for a global decision to change.

You control this behavior with the `health_sources` field on a pool. Regional health works alongside global health, not in place of it.

---

## When to use regional health

Cloudflare runs health checks from multiple data centers in each [health monitor region](/load-balancing/understand-basics/health-details/) on a pool. By default, those results collapse into a single global decision. A pool is globally healthy when health check results from the regions in `check_regions` meet the global health threshold. Your load balancer then steers on that one decision everywhere.

That single decision fits poorly when reachability differs by region. Cloudflare computes it from every region that checks the pool. Depending on the steering policy, some checking regions may never send traffic to that pool. Suppose the network path from one region to a pool degrades. Those failures still count toward the global health decision, even when other regions can reach the pool.

A global health decision can fail in either direction. Other regions may outweigh the affected region, causing it to keep sending traffic to a pool it cannot reach. Alternatively, the regional failures may make the pool globally unhealthy, removing it from regions that can still reach it.

Regional health gives each region its own decision for a pool. A region that cannot reach a pool routes around it. Regions that can reach it keep using it.

Use regional health when:

- **Traffic may reach a pool from multiple regions.** A single global decision may not represent every region's experience.
- **Network conditions vary by region.** Regional health lets health decisions reflect those differences.

### Benefits

- **Faster regional response.** Your load balancer can use a regional decision without waiting for the global decision to change.
- **Independent regional decisions.** Each configured region can reach a different decision for the same pool.
- **Decisions match reachability.** A pool can remain available in regions that can reach it.

Keep the default global behavior when:

- **Only one region checks the pool.** The regional and global decisions are identical.
- **Origins are either fully up or fully down everywhere.** Every region reaches the same decision, so regional health does not change steering.

---

## Health sources

A health source is the scope over which Cloudflare aggregates data center health checks into a decision. Cloudflare supports the following sources:

| Source     | Scope                         | Description                                                                                                                                                                                                                                                 |
| ---------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `local`    | A single data center          | Not a configurable API value. Cloudflare uses `local` automatically only for pools that use All Data Centers health monitoring and do not set `health_sources`. No aggregation occurs, the result comes from the individual data center that ran the check. |
| `regional` | One region                    | Aggregates the checks of all data centers within each region in `check_regions`. Each region produces its own decision.                                                                                                                                     |
| `global`   | The Cloudflare global network | Aggregates every configured region into a single decision. This is the default Load Balancing behavior.                                                                                                                                                     |

The `health_sources` field is an ordered priority list. For each request, your load balancer takes the first source with a decision for that region. It falls back to the next source when none exists.

With `["regional", "global"]`, your load balancer first uses the decision for the region handling the request. If that decision is unavailable, it uses the global decision. For example, this can happen when traffic arrives in a region outside `check_regions`. Regional decisions remain independent while they are available. Traffic using the global fallback follows the global decision.

When `health_sources` is unset, existing pools keep their current behavior until you opt in.

The only accepted values are unset and `["regional", "global"]`.

:::note

Your load balancer may fall back to the `global` source. Cloudflare then compares the copy held at the data center serving the request against the centrally aggregated copy. It uses whichever is more recent.

:::

---

## Regional health compared to check regions

The `check_regions` and `health_sources` fields sound similar but do different jobs:

| Aspect                            | `check_regions`         | `health_sources`                                                     |
| --------------------------------- | ----------------------- | -------------------------------------------------------------------- |
| Controls                          | Where health checks run | How checks turn into a steering decision                             |
| Output                            | Inputs to the decision  | One global decision, or one decision per region with global fallback |
| Can regions disagree about a pool | No                      | Yes, when `health_sources` includes `regional`                       |

Narrowing `check_regions` changes the inputs to the single global decision. It is still one decision, used in every location. Narrowing it cannot make two regions disagree about the same pool. Only `health_sources` with `regional` can.

---

## Example: region-specific reachability failure

Consider a US pool (`pool-us`) and a European pool (`pool-eu`). [Proximity steering](/load-balancing/understand-basics/traffic-steering/steering-policies/proximity-steering/) sends European users to `pool-eu` first. If `pool-eu` becomes unavailable, they fail over to `pool-us`. Because European traffic can reach `pool-us` during failover, its `check_regions` include both North American and European regions.

A transatlantic peering problem makes `pool-us` unreachable from Europe. North America can still reach it. If `pool-eu` also becomes unavailable, European traffic attempts to fail over to `pool-us`.

With global health, the European and North American checks contribute to one decision for `pool-us`. If the pool remains globally healthy, European traffic may attempt to use a pool it cannot reach. If it becomes globally unhealthy, North American traffic loses a pool it can still reach.

With regional health, `pool-us` is unhealthy in Europe and healthy in North America. European traffic does not select `pool-us` and follows the remaining fallback configuration. North American traffic continues to use it.

Regional health only changes behavior when reachability genuinely differs by region. Suppose the endpoints in `pool-us` failed outright. Checks from every region would fail, and your load balancer would fail over everywhere. Global health does the same.

---

## Recommended pool configuration

If traffic can reach the pool from any Cloudflare region, use the following configuration:

```json
{
	"check_regions": ["ALL_REGIONS"],
	"health_sources": ["regional", "global"]
}
```

The `health_sources` field provides a decision for each configured region. Global health covers traffic when no regional decision is available. If only specific regions can send traffic to the pool, list those regions in `check_regions` instead. Traffic arriving outside the configured regions uses the global decision.

---

## Configure regional health

Before you begin, ensure the pool specifies at least one region in `check_regions`.

:::caution

The China Network and FedRAMP High regions each require separate access approval. Without that approval, adding either region to `check_regions` on a regional health pool returns a validation error.

:::

Set `health_sources` to `["regional", "global"]` on the pool:

`PATCH /accounts/{account_id}/load_balancers/pools/{pool_id}`

You can set `health_sources` when you create or modify a pool. Pool responses include the field when it is configured.

---

## Related resources

- [How endpoints and pools become unhealthy](/load-balancing/understand-basics/health-details/)
- [Pools](/load-balancing/pools/)
- [Monitors](/load-balancing/monitors/)
- [Traffic steering](/load-balancing/understand-basics/traffic-steering/)
- [Load Balancing analytics](/load-balancing/reference/load-balancing-analytics/)


# Session affinity



## Types

Session affinity specifies the type of session affinity the load balancer should use unless specified as `"none"` or `""` (default).

### By Cloudflare cookie only

On the first request to a proxied load balancer, a cookie is generated, encoding information of which endpoint the request will be forwarded to. Subsequent requests, by the same client to the same load balancer, will be sent to the endpoint the cookie encodes for the duration of the cookie and as long as the endpoint remains healthy. If the cookie has expired or the endpoint is unhealthy, a new endpoint is calculated and used.

#### How does it work?

### By Cloudflare cookie and Client IP fallback

This behaves similar to `cookie` except the initial endpoint selection is stable and based on the client's IP address.

### By HTTP header

On the first request to a proxied load balancer, a session key based on the configured HTTP headers is generated. The session key encodes the request headers used for storing which endpoint the request will be forwarded to during the load balancer session state. Subsequent requests to the load balancer with the same headers will be sent to the same endpoint, for the duration of the session and as long as the endpoint remains healthy. If the session has been idle for the duration of session affinity TTL seconds or the endpoint is unhealthy, then a new endpoint is calculated and used.

:::note

[Sticky Zero-Downtime Failover](/load-balancing/understand-basics/session-affinity/#zero-downtime-failover) is not supported for session affinity by HTTP header.

:::

#### Control how headers are used

By default, at least one of the HTTP headers that you configure for session affinity by HTTP header must be present on requests sent to your load balancer in order for header-based sessions to be created. If a client adds or removes HTTP headers on their requests and they have already established a session, a new session will be created based on the new HTTP headers found in subsequent requests as long as they are specified in your configuration.

If you would like to require all of your configured HTTP headers to be present on requests in order for sessions to be created, then set `session_affinity_attributes.require_all_headers` to `true` via the Cloudflare API or toggle `Require all headers` to `enabled` in the Cloudflare dashboard when editing your load balancer.

---

## Enabling Session Affinity from the Cloudflare dashboard

Enable Session Affinity when you [create or edit a load balancer](/load-balancing/load-balancers/create-load-balancer/), during the **Hostname** step.

If you enable Session Affinity, choose one of the following options:

- **By Cloudflare cookie only**: Sets a `__cflb` cookie to track the associated endpoint.
- **By Cloudflare cookie and Client IP fallback**: Sets a `__cflb` cookie, but also uses the client IP address when no session affinity cookie is provided.
- **By HTTP header**.

:::caution[Important]

Session Affinity is not supported in [DNS-only mode (gray cloud)](/load-balancing/understand-basics/proxy-modes/). Alternatively, you can use [DNS persistence](/load-balancing/additional-options/dns-persistence/).

:::

---

## Enabling Session Affinity via the Cloudflare API

Session affinity is a property of load balancers, which you can set with the following endpoints:

- [Create a load balancer](/api/resources/load_balancers/methods/create/)
- [Edit a load balancer](/api/resources/load_balancers/methods/update/)

Customize the behavior of session affinity by using the `session_affinity`, `session_affinity_ttl`, and `session_affinity_attributes` parameters.

To enable session affinity by HTTP header, set the `session_affinity` value to `header` and add your
HTTP header names to `session_affinity_attributes.headers`.

For more details on API commands in context, refer to [Create a load balancer with the API](/load-balancing/load-balancers/create-load-balancer/).

---

## Endpoint Drain

Drain or remove all traffic from an endpoint without affecting any active customers using endpoint drain. For more details on endpoint drain, refer to [Performing planned maintenance](/load-balancing/additional-options/planned-maintenance/#gradual-rotation).

:::caution[Important]

Endpoint drain is not supported for load balancers in [DNS-only mode (gray cloud)](/load-balancing/understand-basics/proxy-modes/).

:::

## Zero-Downtime Failover

Zero-Downtime Failover automatically sends traffic to endpoints within a pool during transient network issues. This helps reduce errors shown to your users when issues occur in between active health monitors.

You can enable one of three options:

- **None**: No failover will take place and errors may show to your users.
- **Temporary**: Traffic will be sent to other endpoint(s) until the originally pinned endpoint is available.
- **Sticky**: The session affinity cookie is updated and subsequent requests are sent to the new endpoint moving forward as needed.

:::note

[Sticky Zero-Downtime Failover](/load-balancing/understand-basics/session-affinity/#zero-downtime-failover) is not supported for session affinity by HTTP header.

:::


# Traffic steering

When requests come to your load balancer, it distributes them across your pools and endpoints according to four factors:

1. [Pool and endpoint health](/load-balancing/understand-basics/health-details/): Traffic decisions start with which pools and endpoints are available and should receive traffic.
2. [Pool sets](/load-balancing/understand-basics/traffic-steering/pool-sets/): The preferred way to define new API-managed location routing. A matched pool set can replace pool selection and provide its own steering policy, weights, and fallback pool.
3. [Global traffic steering](/load-balancing/understand-basics/traffic-steering/steering-policies/): Policies set on your [load balancer](/load-balancing/load-balancers/) that route traffic to attached and available pools.
4. [Local traffic steering](/load-balancing/understand-basics/traffic-steering/origin-level-steering/): These are policies set on each [pool](/load-balancing/pools/) that route traffic to available endpoints within the pool.

When a pool or endpoint becomes unhealthy, your load balancer and pools redistribute traffic according to these same policies.

# Pool sets

Pool sets allow you to combine geographic steering with other traffic steering policies. For example, you can apply Dynamic Latency steering within a specific region or country. For load balancers managed through the API, pool sets can replace Geo steering.

With pool sets you can:

- Apply any supported steering policy within a single location
- Set pool weights that apply only to that location
- Assign a fallback pool for that location instead of the global fallback pool
- Return a fixed HTTP response for matched proxied traffic

:::note
Use [Geo steering](/load-balancing/understand-basics/traffic-steering/steering-policies/geo-steering/) for simple, dashboard-managed geographic failover. Geo steering evaluates each location's pools in failover order and uses one global fallback pool. It cannot split traffic across pools within a location.
:::

## How pool sets are evaluated

Pool sets are stored as an ordered array on the load balancer. Cloudflare evaluates them in array order and stops at the first pool set whose `match` succeeds. That pool set then supplies the pools, steering policy, weights, and fallback pool for the request.

A pool set matching a single data center does not automatically take priority over one matching a region. Order the array from most specific to least specific.

Place a default pool set last by setting `match.default` to `true`. The `default` match applies to every request. Since pool sets use first-match wins, this pool set handles requests that did not match an earlier pool set:

```json
{
	"pool_sets": [
		{
			"name": "sjc-only",
			"match": { "topology": { "pops": ["SJC"] } },
			"overrides": { "pools": ["17b5962d775c646f3f9725cbc7a53df4"] }
		},
		{
			"name": "default",
			"match": { "default": true },
			"overrides": { "pools": ["ff02c959d17f7bb2b1184a202e3c0af7"] }
		}
	]
}
```

A pool set with `disabled` set to `true` is skipped.

## Match conditions

The `match` object decides which requests a pool set applies to. Set either `default` or `topology` — the two cannot be combined. A pool set with no `match` at all applies to every request.

| Field      | Description                                                                   |
| ---------- | ----------------------------------------------------------------------------- |
| `default`  | When `true`, matches every request. Cannot be combined with `topology`.        |
| `topology` | Matches by location. Requires at least one of `pops`, `countries`, `regions`. |

### Topology matching

Within `topology`, each field takes a list of location codes:

| Field       | Values                                                                                                                |
| ----------- | --------------------------------------------------------------------------------------------------------------------- |
| `pops`      | Cloudflare data center codes, matched against the data center handling the request                                     |
| `countries` | ISO 3166-1 alpha-2 country codes                                                                                      |
| `regions`   | Cloudflare [region codes](/load-balancing/reference/region-mapping-api/#list-of-load-balancer-regions), such as `WNAM` |

Entries within a single field are combined with OR. A request from Germany matches `"countries": ["FR", "DE", "GB"]`.

:::caution
Fields are combined with AND, not OR. A `topology` that sets both `"countries": ["US"]` and `"regions": ["WNAM"]` matches only requests that are in the United States **and** in the WNAM region. To match either location, use two separate pool sets.
:::

For example, this topology sets multiple values in all three fields:

```json
{
	"match": {
		"topology": {
			"pops": ["SJC", "IAD"],
			"countries": ["US", "CA"],
			"regions": ["WNAM", "ENAM"]
		}
	}
}
```

A request matches when its data center is `SJC` or `IAD`, its country is `US` or `CA`, **and** its region hierarchy includes `WNAM` or `ENAM`.

Set one field per `topology` unless you specifically want that AND behavior.

A `regions` entry matches if it appears anywhere in the request's region hierarchy, so a broader region code can match a request from a narrower one.

Country matching uses the location resolved for the request. When the client location cannot be resolved, country matching falls back to the country of the Cloudflare data center handling the request.

## Overrides

The `overrides` object holds the routing behavior applied on a match. Its fields are optional, but a pool set without `fixed_response` must set `overrides.pools`.

| Field                 | Description                                                                                     |
| --------------------- | ----------------------------------------------------------------------------------------------- |
| `pools`               | Pool IDs to route to. Replaces the load balancer's pool selection entirely for this request.     |
| `pool_weights`        | Per-pool weights, applied only within this pool set                                             |
| `pool_default_weight` | Weight for any pool in `pools` without an entry in `pool_weights`                                |
| `fallback_pool`       | Pool of last resort for this pool set. When omitted, the load balancer's fallback pool is used. |
| `steering_policy`     | Steering policy applied to `pools`                                                               |

`pools` is a flat list rather than a map of locations to pools. The matched pool set defines the whole set of candidate pools for the request.

### Steering policies within a pool set

These steering policies are supported within a pool set:

| Policy                       | Behavior within the pool set                                     |
| ---------------------------- | ---------------------------------------------------------------- |
| `off`                        | Use `pools` in failover order                                    |
| `random`                     | Select a pool at random, honoring `pool_weights`                 |
| `dynamic_latency`            | Select the pool with the lowest round trip time                  |
| `proximity`                  | Select the pool closest to the request by latitude and longitude |
| `least_outstanding_requests` | Select a pool by weights and outstanding request counts          |
| `least_connections`          | Select a pool by weights and open connection counts              |

`pool_weights` and `pool_default_weight` apply to `random`, `least_outstanding_requests`, and `least_connections`. These weights are separate from the load balancer's `random_steering` weights, so each pool set can weight its pools independently.

Omitting `steering_policy` leaves the pool set using failover order.

### Fixed responses

For proxied zone load balancers, a pool set can return a `fixed_response` instead of using `overrides.pools`. Use this option to return an HTTP status or redirect for a matched location:

```json
{
	"pool_sets": [
		{
			"name": "redirect-region",
			"match": { "topology": { "countries": ["US"] } },
			"fixed_response": {
				"status_code": 302,
				"location": "https://example.com/service-unavailable"
			}
		}
	]
}
```

Do not use `fixed_response` with DNS-only load balancers. DNS responses cannot carry HTTP status, body, or redirect fields. A matching fixed response returns `NOERROR` with no records.

A pool set must specify either `overrides.pools` or `fixed_response`. A pool set with neither is rejected, because it would match traffic and then have nowhere to send it.

## Relationship to other steering settings

Pool sets are independent of the standard steering fields. Adding pool sets does not read from or write to `default_pools`, `region_pools`, `country_pools`, `pop_pools`, `steering_policy`, `random_steering`, or `fallback_pool`, and configuring those fields does not create pool sets.

Because a matched pool set replaces pool selection for the request, the standard fields have no effect on requests that a pool set matches. Requests that match no pool set fall through to your standard steering configuration.

`default_pools` remains required on every load balancer, even when you expect every request to match a pool set. It is the destination for requests that match no pool set.

### Custom rules

Pool sets are evaluated before [custom rules](/load-balancing/additional-options/load-balancing-rules/). A matched pool set establishes the routing decision, and custom rules then apply their overrides on top of it.

A pool set that returns a `fixed_response` is the complete response, so custom rules are not evaluated for that request.

## DNS-only load balancers

Country matching depends on the top-level steering policy and `location_strategy`. With a configured strategy, Geo and Proximity steering can use EDNS Client Subnet (ECS), the resolver IP address, or the responding Cloudflare data center. Without a configured strategy, Proximity uses ECS when available, while Geo uses the responding data center. Other top-level policies use the responding data center.

A pool set applies `overrides.steering_policy` after evaluating its match. The override therefore cannot change the location used for country matching. For more information, refer to [EDNS Client Subnet (ECS) support](/load-balancing/understand-basics/traffic-steering/steering-policies/#edns-client-subnet-ecs-support).

## Limits

Pool sets are subject to the following limits:

| Limit                                              | Value |
| -------------------------------------------------- | ----- |
| Pool sets per load balancer                        | 1,000 |
| Characters in `name`                               | 200   |
| Entries per `pops`, `countries`, or `regions` list | 1,000 |

Duplicate entries within a single `pops`, `countries`, or `regions` list are rejected.

:::caution
A pool referenced by a pool set cannot be [deleted](/load-balancing/pools/create-pool/#delete-a-pool) until you remove it from every pool set that references it. This applies to pools in `overrides.pools`, `overrides.pool_weights`, and `overrides.fallback_pool`.
:::

## Configure pool sets via the API

Pool sets are managed through the `pool_sets` field on the [Update Load Balancer](/api/resources/load_balancers/methods/edit/) endpoint. When you send a `PATCH` request:

- Omitting `pool_sets` leaves existing pool sets unchanged
- Sending `"pool_sets": []` removes all pool sets
- Sending `"pool_sets": null` makes no change

### Example request

Before using this example, create the referenced pools. Replace each example pool ID with an ID from your account.

This request splits Western North American traffic across two pools by weight and uses a regional fallback pool. It selects the lowest-latency pool for German traffic. A default pool set handles all remaining traffic. The load balancer uses a separate global fallback pool.

Send a `PATCH` request to `/zones/{zone_id}/load_balancers/{load_balancer_id}` with the following body:

```json title="Request"
{
	"fallback_pool": "6f1ed002ab5595859014ebf0951522d9",
	"pool_sets": [
		{
			"name": "wnam-active-active",
			"match": { "topology": { "regions": ["WNAM"] } },
			"overrides": {
				"pools": [
					"17b5962d775c646f3f9725cbc7a53df4",
					"9290f38c5d07c2e2f4df57b1f61d4196"
				],
				"pool_weights": {
					"17b5962d775c646f3f9725cbc7a53df4": 0.5,
					"9290f38c5d07c2e2f4df57b1f61d4196": 0.5
				},
				"steering_policy": "random",
				"fallback_pool": "2a28d35d1c00f000540fe739a04b3230"
			}
		},
		{
			"name": "de-lowest-latency",
			"match": { "topology": { "countries": ["DE"] } },
			"overrides": {
				"pools": [
					"0930eec54a4c7ae6616985b79f678210",
					"c8b4f5a6d7e84910a2b3c4d5e6f70819"
				],
				"steering_policy": "dynamic_latency"
			}
		},
		{
			"name": "default",
			"match": { "default": true },
			"overrides": {
				"pools": ["ff02c959d17f7bb2b1184a202e3c0af7"],
				"steering_policy": "off"
			}
		}
	]
}
```

### Resulting behavior

After the request completes, the load balancer routes traffic with this configuration:

| Order | Match                         | Pools                                                                      | Steering policy  | Fallback pool                              |
| ----- | ----------------------------- | -------------------------------------------------------------------------- | ---------------- | ------------------------------------------ |
| 1     | Western North America (`WNAM`) | `17b5962d775c646f3f9725cbc7a53df4`, `9290f38c5d07c2e2f4df57b1f61d4196` | Random, 50% each | `2a28d35d1c00f000540fe739a04b3230`         |
| 2     | Germany (`DE`)                | `0930eec54a4c7ae6616985b79f678210`, `c8b4f5a6d7e84910a2b3c4d5e6f70819` | Dynamic Latency  | Global fallback                            |
| 3     | All remaining traffic         | `ff02c959d17f7bb2b1184a202e3c0af7`                                       | Failover order   | Global fallback                            |

The global fallback pool is `6f1ed002ab5595859014ebf0951522d9`.

## Validation errors

Invalid Pool Sets configurations return HTTP status `400` and API error code `1002`. The error message explains the problem and can include one of these identifiers:

| Message identifier             | Cause                                                               |
| ------------------------------ | ------------------------------------------------------------------- |
| `POOL_SETS_TOO_LARGE`          | More than 1,000 pool sets on one load balancer                      |
| `POOL_SET_NO_INTENT`           | A pool set specifies neither `overrides.pools` nor `fixed_response` |
| `POOL_SET_DEFAULT_WITH_MATCH`  | A `match` combines `default` with `topology`                        |
| `POOL_SET_EMPTY_TOPOLOGY`      | A `topology` sets none of `pops`, `countries`, or `regions`         |
| `POOL_SET_TOPOLOGY_TOO_LARGE`  | A `topology` list exceeds 1,000 entries                             |
| `POOL_SET_POP_ENTITLEMENT`     | The account is not entitled to data center steering                 |
| `POOL_SET_REGION_ENTITLEMENT`  | The account is not entitled to region steering                      |
| `POOL_SET_COUNTRY_ENTITLEMENT` | The account is not entitled to country steering                     |

# Hash

**Hash steering** guides Cloudflare to send requests to endpoints based on a combination of [endpoint weights](/load-balancing/understand-basics/traffic-steering/origin-level-steering/#weights) and previous requests from that IP address. Ensures requests from the same IP address will hit the same endpoint, but actual traffic distribution may differ from endpoint weights.

## Limitation when using Workers

Hash Steering relies on the `x-forwarded-for` header to determine the originating IP address of a request. However, when a [Cloudflare Worker](/workers/) is used in front of a load balancer, this can affect how Hash Steering functions.

When a request originates from a browser, it lacks an `x-forwarded-for` header, but if a Worker proxies the request to a load balancer, the header is populated with the Worker's IP instead of the original client IP. Since the Worker's IP — often a Cloudflare public IP — can change between requests, Hash Steering may direct the same client's requests to different endpoints, leading to inconsistent traffic routing.

### Workaround

To ensure Hash Steering works correctly when using a Worker in front of a Load Balancer, manually set the `x-forwarded-for` header in the Worker to the client's original IP address. By manually setting `x-forwarded-for` to `CF-Connecting-IP`, Hash Steering will function as expected, ensuring traffic consistency for end users.

# Local traffic steering



## Policies

 <br />

## Weights

### Customize weights

### Limitations


# Least Outstanding Requests

**Least Outstanding Requests steering** allows you to route traffic to endpoints that currently have the lowest number of outstanding requests.

This steering policy selects an endpoint by taking into consideration endpoint weights, as well as each endpoint's number of in-flight requests. Endpoints with more pending requests are weighted proportionately less in relation to others.

Least Outstanding Requests steering is best to use if your endpoints are easily overwhelmed by a spike in concurrent requests. It supports [adaptive routing](/load-balancing/understand-basics/adaptive-routing/) and [session affinity](/load-balancing/understand-basics/session-affinity/).

## Configure via the API

```json title="Pools"
{
  "origin_steering": {
    "policy": "least_outstanding_requests"
  }
}
```

Refer to the [API documentation](/api/resources/load_balancers/subresources/pools/methods/update/) for more information on the pool configuration.

:::note

Least Outstanding Requests steering can also be configured on a load balancer as a [global traffic steering policy](/load-balancing/understand-basics/traffic-steering/steering-policies/least-outstanding-requests/), taking into account outstanding request counts and `random_steering` weights for pools on the load balancer.
:::

## Limitations

Least Outstanding Requests steering can be configured for pools that are part of [DNS-only load balancers](/load-balancing/understand-basics/proxy-modes/#dns-only-load-balancing), but is only supported in a no-operation form. When endpoint steering logic is applied for a pool on a DNS-only load balancer, all endpoint outstanding request counts are considered to be zero, meaning traffic is served solely based on endpoint weights.

Although it is configurable, it is not recommended to associate pools that use Least Outstanding Requests steering with DNS-only load balancers due to its partial support.

# Random

**Random steering** sends requests to endpoints purely based on [endpoint weights](/load-balancing/understand-basics/traffic-steering/origin-level-steering/#weights). Distributes traffic more accurately, but may cause requests from the same IP to hit different endpoints.

# Dynamic

**Dynamic steering** uses health monitor data to identify the fastest pool for a given Cloudflare Region or data center.

Dynamic steering creates Round Trip Time (RTT) profiles based on an exponential weighted moving average (EWMA) of RTT to determine the fastest pool. If there is no current RTT data for your pool in a region or colocation center, Cloudflare directs traffic to the pools in failover order.

RTT values are collected each time a health probe request is made and based on the response from the endpoint to the monitor request. When a request is made, Cloudflare inspects the RTT data and uses it to sort pools by their RTT values.

When enabling Dynamic steering the first time for a pool, allow 10 minutes for the change to take effect while Cloudflare builds an RTT profile for that pool.

For TCP health monitors, calculated latency may not reflect the true latency to the endpoint if you are terminating TCP at a cloud provider edge location.

The diagram below shows how Cloudflare would route traffic to the pool with the lowest EWMA among three regions: Eastern North America, Europe, and Australia. In this case, the ENAM pool is selected because it has the lowest RTT.

![Dynamic steering routes traffic to the fastest available pool](~/assets/images/load-balancing/traffic-steering-2.png)

:::note

To ensure dynamic steering works as expected, the [Health Monitor Region](/load-balancing/monitors/#health-monitor-regions) must be set to **All Regions**.
The Enterprise-only **All Data Centers** option is also a viable alternative.

:::

# Geo


**Geo steering** directs traffic to pools tied to specific countries, regions, or — for Enterprise customers only — data centers.

This option is extremely useful when you want site visitors to access the endpoint closest to them, which improves page-loading performance.

:::note
For new API-managed location-specific routing, use [pool sets](/load-balancing/understand-basics/traffic-steering/pool-sets/). Pool sets support per-location steering policies, weights, fallback pools, and custom rules. Use Geo steering for simple geographic failover configured in the dashboard.

:::

## Pool assignment

You can assign multiple pools to the same area and the load balancer will use them in failover order. Any options not explicitly defined — whether in data centers, countries, or regions — will fall back to using default pools and failover.

### Region steering

Cloudflare has [13 geographic regions](/load-balancing/reference/region-mapping-api/#list-of-load-balancer-regions) that span the world. The region of a client is determined by the region of the Cloudflare data center that answers the client’s DNS query.

:::caution

If you add a pool to a region, you cannot [delete this pool](/load-balancing/pools/create-pool/#delete-a-pool) until you remove it from the **Geo steering** configuration. The configuration is **not** automatically removed when you change to a different **Traffic Steering** method.
:::

 

### Dashboard

When [creating or editing a load balancer](/load-balancing/load-balancers/create-load-balancer/):

1. Go to the **Traffic steering** step.
2. Select **Geo steering**.
3. For **Region**, select a region > **Add Region**.
4. Select **Edit**.
5. Select a pool > **Add Pool**.
6. If adding multiple pools, re-order them into your preferred failback order.
7. (optional) Add more regions if needed.

 

### API

Use the `regions_pool` property of the [Update Load Balancers](/api/resources/load_balancers/methods/update/) command to specify an array of regions. Specify each region using the [appropriate region code](/load-balancing/reference/region-mapping-api/#list-of-load-balancer-regions) followed by a list of endpoints to use for that region.

In the example below, `WNAM` and `ENAM` represent the West and East Coasts of North America, respectively.

```json title="Request"
// PUT /zones/:zone_id/load_balancers
{
	"description": "Load Balancer for www.example.com",
	"name": "www.example.com",
	"ttl": 30,
	"proxied": true,
	"fallback_pool": "ff02c959d17f7bb2b1184a202e3c0af7",
	"default_pools": [
		"17b5962d775c646f3f9725cbc7a53df4",
		"ff02c959d17f7bb2b1184a202e3c0af7"
	],
	"region_pools": {
		"WNAM": [
			"17b5962d775c646f3f9725cbc7a53df4",
			"ff02c959d17f7bb2b1184a202e3c0af7"
		],
		"ENAM": [
			"17b5962d775c646f3f9725cbc7a53df4",
			"ff02c959d17f7bb2b1184a202e3c0af7"
		],
		"EEU": [
			"ff02c959d17f7bb2b1184a202e3c0af7",
			"17b5962d775c646f3f9725cbc7a53df4"
		]
	}
}
```

If you only define `WNAM`, then traffic from the East Coast will be routed to the `default_pools`. You can test this using a client in each of those locations.

 

### Country steering

 

### Dashboard

When [creating or editing a load balancer](/load-balancing/load-balancers/create-load-balancer/):

1. Follow the [create a load balancer procedure](/load-balancing/load-balancers/create-load-balancer/#create-a-load-balancer) until you reach the **Traffic steering** step.
2. Select **Geo steering**.
3. For **Country**, select a country > **Add Region**.
4. Select **Edit**.
5. Select a pool > **Add Pool**.
6. If adding multiple pools, re-order them into your preferred failback order.
7. (optional) Add more countries if needed.

 

### API

When creating a load balancer [via the API](/api/resources/load_balancers/methods/create/), include the `country_pools` object to map countries to a list of pool IDs (ordered by their failover priority).

To get a list of country codes, use the [Region API](/load-balancing/reference/region-mapping-api/).

Any country not explicitly defined will fall back to using the corresponding `region_pool` mapping (if it exists), then to the associated default pools.

 

### PoP steering

When creating a load balancer [via the API](/api/resources/load_balancers/methods/create/), include the `pop_pools` object to map Cloudflare data centers to a list of pool IDs (ordered by their failover priority).

For help finding data center identifiers, refer to [this community thread](https://community.cloudflare.com/t/is-there-a-way-to-retrieve-cloudflare-pops-list-and-locations-programmatically/234643).

Any data center not explicitly defined will fall back to using the corresponding `country_pool`, then `region_pool` mapping (if it exists), and finally to associated default pools.

:::note
PoP steering is only available to Enterprise customers and only accessible via the API.
:::

### Failover behavior

A fallback pool will be used if there is only one pool in the same region and it is unavailable.
If there are multiple pools in the same region, the order of the pools will be respected. For example, if the first pool is unavailable, the second pool will be used.


# Global traffic steering


 <br />

## EDNS Client Subnet (ECS) support

 EDNS Client Subnet (ECS)  support provides customers with more control over location-based steering during
gray-clouded DNS resolutions and can be used for proximity or geo (country) steering.

Customers can configure their load balancer using the `location_strategy` parameter, which includes the properties `prefer_ecs` and `mode`.

`prefer_ecs` determines whether the ECS geolocation should be preferred as the authoritative location.

| Type          | Description                                                                             |
| ------------- | --------------------------------------------------------------------------------------- |
| `"always"`    | Always prefers ECS.                                                                     |
| `"never"`     | Never prefers ECS.                                                                      |
| `"proximity"` | Prefers ECS only when `steering_policy="proximity"`.                                    |
| `"geo"`       | Prefers ECS only when `steering_policy="geo"` and only supports country-level steering. |

`mode` determines the authoritative location when ECS is not preferred, does not exist in the request, or its geolocation lookup is unsuccessful.

| Type            | Description                                                                                                             |
| --------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `"pop"`         | Uses the Cloudflare PoP location.                                                                                       |
| `"resolver_ip"` | Uses the DNS resolver geolocation data. If the geolocation lookup is unsuccessful, it uses the Cloudflare PoP location. |

:::note

ECS support applies to DNS-only load balancers.

:::


# Least Outstanding Requests

**Least Outstanding Requests steering** allows you to route traffic to pools that currently have the lowest number of outstanding requests.

This steering policy selects a pool by taking into consideration `random_steering` weights, as well as each pool's number of in-flight requests. Pools with more pending requests are weighted proportionately less in relation to others.

Least Outstanding Requests steering is best to use if your pools are easily overwhelmed by a spike in concurrent requests. This steering method lends itself to applications that value server health above latency, geographic alignment, or other metrics. It takes into account the [pool's health status](/load-balancing/understand-basics/health-details/#how-a-pool-becomes-unhealthy), [adaptive routing](/load-balancing/understand-basics/adaptive-routing/), and [session affinity](/load-balancing/understand-basics/session-affinity/).

## Configure via the API

```json title="Load Balancers"
{
  "steering_policy": "least_outstanding_requests"
}
```

Refer to the [API documentation](/api/resources/load_balancers/methods/update/) for more information on the load balancer configuration.

:::note

Least Outstanding Requests steering can also be configured on a pool as a [local traffic steering policy](/load-balancing/understand-basics/traffic-steering/origin-level-steering/least-outstanding-requests-pools/), taking into account outstanding request counts and weights for endpoints within the pool.
:::

## Limitations

Least Outstanding Requests steering can be configured for [DNS-only load balancers](/load-balancing/understand-basics/proxy-modes/#dns-only-load-balancing), but is only supported in a no-operation form. For DNS-only load balancers, all pool outstanding request counts are considered to be zero, meaning traffic is served solely based on `random_steering` weights.

Although it is configurable, it is not recommended to use Least Outstanding Requests steering for DNS-only load balancers due to its partial support.

# Proximity

**Proximity steering** routes visitors or internal services to the closest physical data center.

To use proximity steering on a load balancer, you first need to add GPS coordinates to each pool.

## When to add proximity steering

* For new pools, add GPS coordinates when you create a pool.
* For existing pools, add GPS coordinates when [managing pools](/load-balancing/pools/create-pool/#edit-a-pool) or in the **Add Traffic steering** step of [creating a load balancer](/load-balancing/load-balancers/create-load-balancer/).

## How to add proximity steering

To add coordinates when creating or editing a pool:

1. Click the *Configure coordinates for Proximity Steering* dropdown.
2. Enter the latitude and longitude or drag a marker on the map.
3. Select **Save**.

:::caution[Warning:]

For accurate proximity steering, add GPS coordinates to all pools within the same load balancer.

:::


# Standard

**Standard steering** policies include **Off - Failover** and **Random**.

These are the only steering policies available to non-Enterprise customers who have not purchased **Traffic steering**.

## Off - Failover

Failover steering uses the pool order to determine failover priority (the failover order).

Failover directs traffic from unhealthy pools — determined by [health monitors](/load-balancing/monitors/) and the **Health Threshold** — to the next healthy pool in the configuration. Customers commonly use this option to set up [active - passive failover](/load-balancing/load-balancers/common-configurations/#active---passive-failover).

If all pools are marked unhealthy, Load Balancing will direct traffic to the fallback pool. The default fallback pool is the last pool listed in the Load Balancing configuration.

If no monitors are attached to the load balancer, it will direct traffic to the primary pool exclusively.

### Failback behavior

In an active/standby setup, with two origin pools:

- Traffic always routes to Pool 1 (the primary pool) unless it becomes unhealthy.
- If Pool 1 is marked unhealthy, traffic shifts to Pool 2 (the standby pool).
- Once Pool 1 becomes healthy again, traffic automatically shifts back to Pool 1, assuming no [session affinity](/load-balancing/understand-basics/session-affinity/) or other settings require subsequent requests to stay at Pool 2.

This behavior is known as failback and ensures traffic resumes normal routing when the primary pool recovers.

## Random steering

Choose **Random** to route traffic to a healthy pool at random. Customers can use this option to set up [active - active failover](/load-balancing/load-balancers/common-configurations/#active---active-failover) (also known as round robin), where traffic is split equally between multiple pools.

Similar to setting Weights to direct the amount of traffic going to each endpoint, customers can also set Weights on pools via the [API's](/api/resources/load_balancers/methods/create/) `random_steering` object to determine the percentage of traffic sent to each pool.