Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,4 @@ export { default as ResourcesBySelector } from "./components/cf/ResourcesBySelec
export { default as SubtractIPCalculator } from "./components/react/SubtractIPCalculator";
export { AgentPrimitivesDiagram } from "./components/react/diagram-showcase/AgentPrimitivesDiagram";
export { default as MeshHostnameRoutingDiagram } from "./components/cf/MeshHostnameRoutingDiagram.astro";
export { default as TunnelHostnameRoutingDiagram } from "./components/cf/TunnelHostnameRoutingDiagram.astro";
2 changes: 1 addition & 1 deletion src/components/cf/MeshHostnameRoutingDiagram.astro
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import { Icon as AstroIcon } from "astro-icon/components";
IP.
</p>
<div class="pill-row">
<span class="token-pill"><code>100.80.0.0/16</code></span>
<span class="token-pill"><code>172.64.128.0/20</code></span>
</div>
</div>
</li>
Expand Down
302 changes: 302 additions & 0 deletions src/components/cf/TunnelHostnameRoutingDiagram.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
---
/* `role="list"` on the `<ol>` below is intentional, not redundant: Safari
+ VoiceOver drop the implicit list role when `list-style: none` is
applied, so the explicit role is required to preserve list semantics
for screen reader users. */
/* eslint-disable astro/jsx-a11y/no-redundant-roles */
import { Icon as AstroIcon } from "astro-icon/components";
---

<figure
class="tunnel-hostname-diagram not-content"
aria-label="How hostname routing works with Cloudflare Tunnel: a client requests a hostname, Cloudflare Gateway assigns a token IP and rewrites the destination, and the tunnel delivers the traffic to a private host on your network or egresses it to the public Internet"
>
<ol class="flow" role="list">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <eslint.rules.astro/jsx-a11y/no-redundant-roles> reported by reviewdog 🐶
The element ol has an implicit role of list. Defining this explicitly is redundant and should be avoided. (astro/jsx-a11y/no-redundant-roles)

<li class="flow-step">
<div class="node-card client-card">
<div class="node-header">
<span class="node-icon client-icon" aria-hidden="true"
><AstroIcon name="warp-client" /></span
>
<a
class="node-title"
href="/cloudflare-one/team-and-resources/devices/cloudflare-one-client/"
>Client device</a
>
</div>
<p class="node-caption">
Requests <code>wiki.internal.local</code>
</p>
</div>
</li>

<li class="flow-connector">
<span class="connector-label">DNS query</span>
<span class="connector-arrow" aria-hidden="true">↓</span>
</li>

<li class="flow-step">
<div class="node-card gateway-card">
<div class="node-header">
<span class="node-icon gateway-icon" aria-hidden="true"
><AstroIcon name="gateway" /></span
>
<a class="node-title" href="/cloudflare-one/traffic-policies/"
>Cloudflare Gateway</a
>
</div>
<p class="node-caption">
Returns a token IP, then rewrites the destination to the real IP.
</p>
<div class="pill-row">
<span class="token-pill"><code>172.64.128.0/20</code></span>
</div>
</div>
</li>

<li class="flow-connector">
<span class="connector-label">Hostname route</span>
<span class="connector-arrow" aria-hidden="true">↓</span>
</li>

<li class="flow-step">
<div class="node-card tunnel-card">
<div class="node-header">
<span class="node-icon tunnel-icon" aria-hidden="true"
><AstroIcon name="tunnel" /></span
>
<a
class="node-title"
href="/cloudflare-one/networks/connectors/cloudflare-tunnel/"
>Cloudflare Tunnel</a
>
</div>
<p class="node-caption">
Forwards traffic to your private network, or egresses it to the public
Internet
</p>
</div>
</li>

<li class="flow-connector" aria-hidden="true">
<span class="connector-arrow">↓</span>
</li>

<li class="flow-step">
<div class="node-card host-card">
<div class="node-header">
<span class="node-icon host-icon" aria-hidden="true"
><AstroIcon name="dns" /></span
>
<span class="node-title">Private host</span>
</div>
<p class="node-caption">
<code>wiki.internal.local</code> · <code>10.0.0.50</code>
</p>
</div>
</li>
</ol>
</figure>

<style>
.tunnel-hostname-diagram {
--map-bg: light-dark(#fafafa, #0f0f10);
--map-card: light-dark(#ffffff, #171719);
--map-elevated: light-dark(#fafafa, #111113);
--map-line: light-dark(rgb(0 0 0 / 12%), rgb(255 255 255 / 14%));
--map-text: light-dark(#171717, #f5f5f5);
--map-strong: light-dark(#525252, #a3a3a3);
--map-caption: light-dark(#737373, #a3a3a3);
--map-brand: #f6821f;
--map-tunnel: light-dark(#4f46e5, #818cf8);
--map-gateway: light-dark(#0ea5e9, #38bdf8);
--map-host: light-dark(#10b981, #34d399);

display: flex;
flex-direction: column;
gap: 12px;
margin: 1.25rem 0;
padding: 18px;
border: 1px solid var(--map-line);
border-radius: 12px;
background:
radial-gradient(circle, var(--map-line) 1px, transparent 1px),
var(--map-bg);
background-size: 14px 14px;
font-family: "Inter Variable", ui-sans-serif, system-ui, sans-serif;
font-feature-settings: "cv02", "cv03", "cv04", "calt";
-webkit-font-smoothing: antialiased;
letter-spacing: -0.01em;
}

.tunnel-hostname-diagram a {
color: inherit;
text-decoration: none;
}

.flow {
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
margin: 0;
padding: 0;
list-style: none;
}

.flow-step {
display: block;
width: 100%;
max-width: 360px;
}

.node-card {
display: flex;
flex-direction: column;
gap: 8px;
padding: 12px 14px;
border: 1px solid var(--map-line);
border-radius: 10px;
background: var(--map-card);
box-shadow: 0 5px 14px rgb(0 0 0 / 7%);
color: var(--map-text);
}

.node-header {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
}

.node-title {
min-width: 0;
color: var(--map-text);
font-size: 14px;
font-weight: 600;
letter-spacing: -0.01em;
}

a.node-title {
transition: color 150ms ease;
}

a.node-title:hover {
color: var(--map-brand);
}

.node-icon {
display: inline-flex;
flex: 0 0 auto;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border-radius: 7px;
font-size: 14px;
font-weight: 600;
}

.node-icon :global(svg) {
width: 18px;
height: 18px;
fill: currentColor;
}

.client-icon {
background: color-mix(in srgb, var(--map-brand) 14%, transparent);
color: var(--map-brand);
}

.gateway-icon {
background: color-mix(in srgb, var(--map-gateway) 14%, transparent);
color: var(--map-gateway);
}

.tunnel-icon {
background: color-mix(in srgb, var(--map-tunnel) 14%, transparent);
color: var(--map-tunnel);
}

.host-icon {
background: color-mix(in srgb, var(--map-host) 14%, transparent);
color: var(--map-host);
}

.node-caption {
margin: 0;
color: var(--map-caption);
font-size: 12px;
line-height: 1.5;
text-align: center;
}

.node-caption code {
display: inline;
padding: 1px 6px;
border: 1px solid var(--map-line);
border-radius: 5px;
background: var(--map-elevated);
color: var(--map-text);
font-family:
"Paper Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
monospace;
font-size: 11px;
white-space: nowrap;
}

.flow-connector {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
padding: 2px 0;
color: var(--map-strong);
}

.connector-label {
color: var(--map-caption);
font-family:
"Paper Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
monospace;
font-size: 11px;
font-weight: 500;
line-height: 1;
}

.connector-arrow {
font-size: 18px;
line-height: 1;
color: var(--map-strong);
}

.pill-row {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 6px;
}

.token-pill {
display: inline-flex;
align-items: center;
padding: 4px 10px;
border: 1px solid
color-mix(in srgb, var(--map-gateway) 35%, var(--map-line));
border-radius: 6px;
background: color-mix(in srgb, var(--map-gateway) 6%, var(--map-card));
}

.token-pill code {
padding: 0;
border: 0;
background: transparent;
color: var(--map-gateway);
font-family:
"Paper Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
monospace;
font-size: 11px;
white-space: nowrap;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
title: Hostname routing is now generally available, with a new public IP range for initial resolved IPs

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want it to be Tunnel Hostname? or something that calls out what kind of routing it is.

Just thinking about when your changelog gets posted on twitter and stuff like that, might need one extra identifier.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works for both Tunnel and Mesh, so trying to go generic here :)

description: Hostname routing is now GA. Initial resolved IPs are moving to a public Cloudflare IP range instead of CGNAT, resolving a conflict with Chromium's Local Network Access restrictions.
products:
- tunnel
- cloudflare-tunnel-sase
- mesh
- gateway
- cloudflare-one
date: 2026-08-12
---

import { DashButton, Render, GlossaryTooltip } from "~/components";

[Hostname routing](https://blog.cloudflare.com/tunnel-hostname-routing/) is now generally available. Instead of managing static IP lists and routes, you can route traffic by hostname across multiple Cloudflare One connectors:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not clear what "route traffic by hostname across multiple connectors means"

I would be more explicit here maybe. like:

Tunnel hostname routing now supports routing traffic across multiple Cloudflare One Connectors with a dynamic set of IPs (? or something). Previously, you had to manage static IP address lists.


- **Cloudflare Tunnel**: route a [private hostname](/cloudflare-one/networks/connectors/cloudflare-tunnel/private-net/cloudflared/connect-private-hostname/) (for example, `wiki.internal.local`) to a private application behind your tunnel, or a [public hostname](/cloudflare-one/traffic-policies/egress-policies/egress-cloudflared/) (for example, `bank.example.com`) to egress through a specific tunnel and anchor traffic to a dedicated exit node.
- **Cloudflare Mesh**: attract a [private or public hostname's traffic](/cloudflare-one/networks/connectors/cloudflare-mesh/routes/#hostname-routes) to a Mesh node.

Alongside GA, the default IPv4 range used for <GlossaryTooltip term="initial resolved IP">initial resolved IPs</GlossaryTooltip> (also called token IPs) is changing from a Carrier-Grade NAT (CGNAT) range to a public Cloudflare-owned range:

<Render file="gateway/egress-selector-cgnat-ips" product="cloudflare-one" />

**Why this is changing:** Starting with [Chrome 142](https://developer.chrome.com/release-notes/142), Local Network Access (LNA) restrictions block background requests to CGNAT addresses (`100.64.0.0/10`), which included the previous initial resolved IP default (`100.80.0.0/16`). LNA is implemented at the Chromium engine level, so it affects all Chromium-based browsers (for example, Microsoft Edge, Brave, and Opera), not only Google Chrome. This could silently break hostname-based Gateway features for users of these browsers, and required Chrome Enterprise policy workarounds. The new default range is public Cloudflare address space, so it is not affected by this restriction.

**What is affected:** Initial resolved IPs are used by several features that associate a DNS query with the network connection that follows it:

- [Private](/cloudflare-one/networks/connectors/cloudflare-tunnel/private-net/cloudflared/connect-private-hostname/) and [public](/cloudflare-one/traffic-policies/egress-policies/egress-cloudflared/) hostname routing for Cloudflare Tunnel
- [Hostname routes](/cloudflare-one/networks/connectors/cloudflare-mesh/routes/#hostname-routes) for Cloudflare Mesh
- [Access private applications](/cloudflare-one/access-controls/applications/non-http/self-hosted-private-app/) on non-HTTPS ports
- [Egress policy host selectors](/cloudflare-one/traffic-policies/egress-policies/host-selectors/) (Domain, Host, Application, and Content Categories)

**Rollout:** Cloudflare is migrating all accounts to the new default range over the next few days. Once migration is complete, you can check your account's current range, or configure a custom range, at any time from **Networking** > **IP addresses** > **Address space** > **Custom IPs**, or using the [Initial Resolved IP Subnet API](/api/resources/zero_trust/subresources/networks/subresources/subnets/#(resource)%20zero_trust.networks.subnets.initial_resolved_ip).

<DashButton url="/?to=/:account/ip-addresses/address-space/custom-ips" />

For full instructions, refer to [Configure initial resolved IPs](/cloudflare-one/networks/routes/configure-initial-resolved-ips/). The IPv6 range (`2606:4700:0cf1:4000::/64`) is unchanged and is not affected by this restriction.

If you were relying on a Chrome Enterprise policy workaround (such as `LocalNetworkAccessRestrictionsTemporaryOptOut`) while your account was still on the legacy CGNAT-based range, refer to [Google Chrome restricts access to private hostnames](/cloudflare-one/networks/connectors/cloudflare-tunnel/private-net/cloudflared/connect-private-hostname/#google-chrome-restricts-access-to-private-hostnames) for next steps.
5 changes: 5 additions & 0 deletions src/content/dash-routes/core-manually-defined.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
"name": "Virtual networks",
"parent": ["Networking", "Routes"]
},
{
"deeplink": "/?to=/:account/ip-addresses/address-space/custom-ips",
"name": "Custom IPs",
"parent": ["Networking", "IP addresses", "Address space"]
},
{
"deeplink": "/?to=/:account/data-catalog/overview",
"name": "R2 Data Catalog",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ This feature replaces the legacy [private network app type](/cloudflare-one/acce

:::note
- **HTTPS applications**: Private hostnames explicitly set to port `443` (not including port ranges such as `441-444`) must have a valid Server Name Indicator (SNI).
- **Non-HTTPS applications**: Private hostnames on non-`443` ports do not require a valid SNI value will be assigned an <GlossaryTooltip term="initial resolved IP">initial resolved IP</GlossaryTooltip> in the CGNAT space. Ensure that the following IP addresses are not blocked by any firewalls or excluded from Gateway traffic:
- **Non-HTTPS applications**: Private hostnames on non-`443` ports do not require a valid SNI value and will be assigned an <GlossaryTooltip term="initial resolved IP">initial resolved IP</GlossaryTooltip>. Ensure that the following IP addresses are not blocked by any firewalls or excluded from Gateway traffic:

<Render file="gateway/egress-selector-cgnat-ips" product="cloudflare-one"/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Depending on your Cloudflare networking configuration, you may need to remove ad
In Include mode, add the following to your include list:

- `100.96.0.0/12` — Mesh IPs (device IPs)
- `100.80.0.0/16` and `2606:4700:0cf1:4000::/64` — Hostname routing (if used)
- `172.64.128.0/20` and `2606:4700:0cf1:4000::/64` — Hostname routing (if used)
- Any CIDR routes you have [configured for your Mesh nodes](/cloudflare-one/networks/connectors/cloudflare-mesh/routes/)

## Firewall considerations
Expand Down
Loading
Loading