|
| 1 | +--- |
| 2 | +pcx_content_type: concept |
| 3 | +title: Public load balancers |
| 4 | +sidebar: |
| 5 | + order: 3 |
| 6 | +--- |
| 7 | + |
| 8 | +import { Render, TabItem, Tabs } from "~/components"; |
| 9 | + |
| 10 | +A [public load balancer](/load-balancing/load-balancers/) allows you to distribute traffic across the servers that are running your [published applications](/cloudflare-one/connections/connect-networks/routing-to-tunnel/). When you add a [published application route]() to your Cloudflare Tunnel, Cloudflare generates a subdomain of `cfargotunnel.com` with the UUID of the created tunnel. `<UUID>.cfargotunnel.com` as if it were a public load balancer endpoint. |
| 11 | + |
| 12 | +Unlike publicly routable IP addresses, the subdomain will only proxy traffic for a load balancer pool in the same Cloudflare account. If someone discovers your subdomain UUID, they will not be able to create a DNS record in another account or system to proxy traffic to the address. |
| 13 | + |
| 14 | +The DNS record (`UUID.cfargotunnel.com`) for each Cloudflare Tunnel is the load balancer endpoint address. Host header is required for tunnel endpoints. |
| 15 | + |
| 16 | +### Option 1: One tunnel per app |
| 17 | +```mermaid |
| 18 | +graph LR |
| 19 | + subgraph LB["Public load balancer <br> app.example.com "] |
| 20 | + subgraph P1[Pool 1] |
| 21 | + E1(["**Endpoint:** <UUID_1>.cfargotunnel.com<br> **Host header**: app1.example.com"]) |
| 22 | + end |
| 23 | + subgraph P2[Pool 2] |
| 24 | + E2(["**Endpoint:** <UUID_2>.cfargotunnel.com<br> **Host header**: app2.example.com"]) |
| 25 | + end |
| 26 | + end |
| 27 | + R@{ shape: text, label: "app.example.com" } |
| 28 | + R--> LB |
| 29 | + P1 -- Tunnel 1 --> cf1 |
| 30 | + P2 -- Tunnel 2 --> cf2 |
| 31 | + subgraph D2[Private network] |
| 32 | + cf1[cloudflared <br> **Route:** app1.example.com] |
| 33 | + S1(["App1<br> 10.0.0.1:80"]) |
| 34 | + cf1-->S1 |
| 35 | + cf2[cloudflared <br> **Route:** app2.example.com] |
| 36 | + S3(["App2 <br> 10.0.0.2:80"]) |
| 37 | + cf2-->S3 |
| 38 | + end |
| 39 | +``` |
| 40 | + |
| 41 | +Only valid for active-standby setups, since each pool has only one endpoint. |
| 42 | + |
| 43 | +### Option 2: Two tunnels, each tunnel connects to both apps |
| 44 | + |
| 45 | +```mermaid |
| 46 | +graph LR |
| 47 | + subgraph LB["Public load balancer <br> app.example.com "] |
| 48 | + subgraph P1[Pool 1] |
| 49 | + E1(["**Endpoint:** <UUID_1>.cfargotunnel.com<br> **Host header**: app1.example.com"]) |
| 50 | + E2(["**Endpoint:** <UUID_2>.cfargotunnel.com<br> **Host header**: app2.example.com"]) |
| 51 | + end |
| 52 | + subgraph P2[Pool 2] |
| 53 | + E3(["**Endpoint:** <UUID_1>.cfargotunnel.com<br> **Host header**: app1.example.com"]) |
| 54 | + E4(["**Endpoint:** <UUID_2>.cfargotunnel.com<br> **Host header**: app2.example.com"]) |
| 55 | + end |
| 56 | + end |
| 57 | + R@{ shape: text, label: "app.example.com" } |
| 58 | + R--> LB |
| 59 | + E1 -- Tunnel 1 -->cf1 |
| 60 | + E3 -- Tunnel 1 --> cf1 |
| 61 | + E2 -- Tunnel 2 --> cf2 |
| 62 | + E4 -- Tunnel 2 --> cf2 |
| 63 | +
|
| 64 | + subgraph N[Private network] |
| 65 | + cf2[cloudflared <br> **Route:** app1.example.com <br> **Route:** app2.example.com] |
| 66 | + S3(["App1 <br> 10.0.0.1:80"]) |
| 67 | + cf2-->S3 |
| 68 | + cf2-->S1 |
| 69 | + cf1[cloudflared <br> **Route:** app1.example.com <br> **Route:** app2.example.com] |
| 70 | + S1(["App2 <br> 10.0.0.2:80"]) |
| 71 | + cf1-->S1 |
| 72 | + cf1-->S3 |
| 73 | + end |
| 74 | +``` |
| 75 | + |
| 76 | +good for an [Active-active](/load-balancing/load-balancers/common-configurations/#active---active-failover) setup which distributes traffic to endpoints in the same pool |
| 77 | +Active-active uses all available instances to process requests simultaneously, providing better performance and scalability by load-balancing traffic across them |
| 78 | + |
| 79 | +### Option 3: One tunnel for both apps |
| 80 | + |
| 81 | +```mermaid |
| 82 | +graph LR |
| 83 | + subgraph LB["Public load balancer <br> app.example.com "] |
| 84 | + subgraph P1[Pool 1] |
| 85 | + E1(["**Endpoint:** <UUID_1>.cfargotunnel.com<br> **Host header**: app1.example.com"]) |
| 86 | + end |
| 87 | + subgraph P2[Pool 2] |
| 88 | + E2(["**Endpoint:** <UUID_1>.cfargotunnel.com<br> **Host header**: app2.example.com"]) |
| 89 | + end |
| 90 | + end |
| 91 | + R@{ shape: text, label: "app.example.com" } |
| 92 | + R--> LB |
| 93 | + P1 -- Tunnel 1 --> cf1 |
| 94 | + P2 -- Tunnel 1 --> cf1 |
| 95 | + subgraph D2[Private network] |
| 96 | + cf1@{ shape: processes, label: "cloudflared <br> **Route:** app1.example.com <br> **Route:** app2.example.com" } |
| 97 | + S3(["App1 <br> 10.0.0.1:80"]) |
| 98 | + S1(["App2 <br> 10.0.0.2:80"]) |
| 99 | + cf1-->S1 |
| 100 | + cf1-->S3 |
| 101 | + end |
| 102 | +``` |
| 103 | + |
| 104 | +Only valid for active-standby LB setups, since each pool has only one endpoint. |
| 105 | + |
| 106 | +Easier to manage if all apps are in the same physical location. Recommend Option 1 if apps are in different geographic locations. |
| 107 | + |
| 108 | +Note: A single origin pool in LB can't have the same Tunnel GUID referenced twice |
| 109 | + |
| 110 | +Deploy replicas for server redundancy. replicas operate in pooled mode. |
| 111 | + |
| 112 | + |
| 113 | + |
| 114 | +## Add a tunnel to a load balancer pool |
| 115 | + |
| 116 | +<Tabs> <TabItem label="Dashboard"> |
| 117 | + |
| 118 | +To create a load balancer, refer to the [Load Balancing documentation](/load-balancing/load-balancers/create-load-balancer/). The endpoint address is the subdomain of your tunnel, `<UUID>.cfargotunnel.com`. |
| 119 | + |
| 120 | +If you want to add a [monitor](/load-balancing/monitors/) to your load balancer pool, you will need to add a host header to **Advanced health check settings**. The header will be similar to `Header Name: Host` and `Value: www.your-zone.com`. The monitor will not work without the host header if you are using a config file that defines the `ingress` field, as shown in [this example](https://github.com/cloudflare/argo-tunnel-examples/blob/adb44da43ec0aa65f7928613b762a47ae0d9b2b0/named-tunnel-k8s/cloudflared.yaml#L90). |
| 121 | + |
| 122 | +</TabItem> |
| 123 | + |
| 124 | +<TabItem label="cli"> |
| 125 | + |
| 126 | +You can add Cloudflare Tunnel to an existing load balancer pool directly from `cloudflared`: |
| 127 | + |
| 128 | +```sh |
| 129 | +cloudflared tunnel route lb <tunnel name/uuid> <hostname> <load balancer pool> |
| 130 | +``` |
| 131 | + |
| 132 | +- `<hostname>`: the DNS hostname of the load balancer, for example `lb.example.com`. |
| 133 | + |
| 134 | +- `<load balancer pool>`: the name of the [pool](/load-balancing/pools/create-pool/#create-a-pool) that will contain the tunnel subdomain. |
| 135 | + |
| 136 | +This command creates an LB DNS record that points the specified hostname to the subdomain of your tunnel (`<UUID>.cfargotunnel.com`). Traffic will not be proxied unless the tunnel is running. |
| 137 | + |
| 138 | +:::note |
| 139 | + |
| 140 | +To create DNS records using `cloudflared`, the [`cert.pem`](/cloudflare-one/connections/connect-networks/do-more-with-tunnels/local-management/local-tunnel-terms/#certpem) file must be installed on your system. |
| 141 | +::: |
| 142 | + |
| 143 | +</TabItem> |
| 144 | + |
| 145 | +</Tabs> |
| 146 | + |
| 147 | +## Optional Cloudflare settings |
| 148 | + |
| 149 | +The application will default to the Cloudflare settings for the load balancer hostname, including [cache rules](/cache/how-to/cache-rules/) and [firewall policies](/firewall/). You can change the settings for your hostname in the [Cloudflare dashboard](https://dash.cloudflare.com/). |
| 150 | + |
| 151 | +## Known limitations |
| 152 | + |
| 153 | +### Monitors and TCP Tunnel origins |
| 154 | + |
| 155 | +If you have a tunnel to a port or SSH port, do not run a TCP health check. |
| 156 | + |
| 157 | +Instead, set up a health check endpoint in `cloudflared` — for example, an [ingress entry rule](/cloudflare-one/connections/connect-networks/do-more-with-tunnels/local-management/configuration-file/#file-structure-for-public-hostnames) that returns a fixed HTTP status response — and create an **HTTP** [monitor](/load-balancing/monitors/) for that endpoint. The monitor will only verify that your server is reachable. It does not check whether the server is running and accepting requests. |
| 158 | + |
| 159 | +### Session affinity and replicas |
| 160 | + |
| 161 | +The load balancer does not distinguish between [replicas](/cloudflare-one/connections/connect-networks/configure-tunnels/tunnel-availability/) of the same tunnel. If you run the same tunnel UUID on two separate hosts, the load balancer treats both hosts as a single endpoint. To maintain [session affinity](/load-balancing/understand-basics/session-affinity/) between a client and a particular host, you will need to connect each host to Cloudflare using a different tunnel UUID. |
| 162 | + |
| 163 | +### Local connection preference |
| 164 | + |
| 165 | +If you notice traffic imbalances across endpoints in different locations, you may have to adjust your load balancer setup. |
| 166 | + |
| 167 | +`cloudflared` connections give preference to tunnels that terminate in the same Cloudflare data center. This behavior can impact how connections are weighted and traffic is distributed. |
| 168 | + |
| 169 | +The solution depends on the type of tunnel being used. If running [legacy tunnels](/cloudflare-one/connections/connect-networks/do-more-with-tunnels/migrate-legacy-tunnels/), put your origins in different pools. If running [Cloudflare tunnel replicas](/cloudflare-one/connections/connect-networks/configure-tunnels/tunnel-availability/) (using a shared ID), switch to separate Cloudflare tunnels as distinct origins. |
0 commit comments