How it works

Encrypted Client Hello, explained plainly

7 min read

A modern TLS handshake encrypts nearly everything about the conversation, including the server's certificate. One field held out: the hostname you asked for, written in the clear in the first packet your browser sends. Encrypted Client Hello closes that gap, but only when several things outside your browser line up.

Why the hostname stayed readable

One IP address commonly serves thousands of names — a CDN edge node, a shared hosting box, a reverse proxy in front of internal services — and each has to know which site you want before it can pick the right certificate. Server Name Indication solved that by putting the hostname into the ClientHello, the browser's opening message. At that moment no keys have been negotiated, so the field cannot be encrypted with a session key that does not exist yet. TLS 1.3 moved the server's certificate under encryption, but the client's first message stayed readable to anything on the path.

An earlier design called ESNI encrypted only the SNI field, using a key published in a DNS TXT record. It was abandoned: versioning was awkward and the rest of the ClientHello stayed open. ECH is a different design, not a rename, and it reached the standards track as RFC 9849 in March 2026.

Outer hello, inner hello

ECH escapes the chicken-and-egg problem by moving the key exchange off the connection. The site's provider generates a keypair and publishes the public half in DNS. Your browser fetches it before connecting, builds the real ClientHello — true hostname, ALPN, full extension set — encrypts that message under the published key, and ships the ciphertext as one extension inside a second, decoy ClientHello.

The outer message carries a public name: a cover hostname belonging to the provider and shared by every site it fronts. An observer reads the outer name and learns which provider you reached, not which of its customers. The front end decrypts the inner message and routes the connection to the right backend.

If it cannot decrypt — a rotated key, a stale cached DNS answer — the handshake does not collapse: the server completes it under the public name, presents a certificate for that name, and can hand back a fresh key to retry with. The real hostname still never appeared in the clear.

The dependency chain, and where it breaks

Three things must line up before a connection can use ECH:

  • A published record. The provider has to publish an HTTPS-type DNS record (type 65) for that hostname carrying an ech= parameter. Plenty of large, well-run sites publish none.
  • A lookup that reaches you intact. A resolver that strips unfamiliar parameters, answers HTTPS queries with an empty response, or an entry pinned in your hosts file removes the key before the browser sees it.
  • A front end that accepts it. The provider's edge must hold the matching private key and serve that hostname over ECH.

Break any one and nothing appears to break. The browser sends an ordinary ClientHello with the hostname in plain text and the page loads normally. No indicator, no warning, no downgrade notice — which is why so many people are sure they have ECH without ever having checked.

Encrypted DNS is the fourth link. Chromium-based browsers use ECH whenever they can resolve the record at all, encrypted or not; if that lookup went out over plaintext port 53, the hostname was on the wire a moment before the handshake hid it. Firefox is stricter: it long required its own encrypted resolver, and since version 129 it will also take the record from the OS resolver — except on macOS, where a DNS integration bug still makes encrypted DNS a precondition. Either way: ECH without encrypted DNS protects the second half of a two-part disclosure.

What stays visible regardless

  • The destination address. Encrypting the name does not change where the packets go.
  • Timing. When the connection opened, how long it stayed up, how often it comes back.
  • Volume and shape. Bytes in each direction, packet sizes, burst patterns — enough on their own to tell a video stream from a chat session.
  • The DNS lookup, unless that was encrypted too.
  • Everything above the transport at both endpoints. ECH is a handshake feature, not an end-to-end one.

On a large shared front end, one IP stands for a huge number of names and tells an observer little. For a site on its own address, the address is the name, and ECH removes nothing that mattered. It hides one string, worth as much as the number of sites sharing that address.

How this interacts with a tunnel

Inside a VPN or proxy tunnel the local network sees an encrypted stream to the exit and nothing else — no hostname, ECH or not — so on that first segment ECH changes nothing. It applies to the second segment: the exit forwards your handshake bytes onward, so the exit and everything past it see the ClientHello — a cover name with ECH, the site without. The destination address stays visible there either way, as does the DNS lookup if it leaves the exit in the clear.

How to check a specific connection

  1. 1Query the site's HTTPS-type DNS record and look for an ech= parameter. Without it, no browser will use ECH for that hostname whatever its settings say. The base64 value decodes to a config holding the cover name.
  2. 2Turn on encrypted DNS in the browser itself, so the lookup does not disclose the name.
  3. 3Load a diagnostic endpoint that reports the handshake it just received. Sites behind Cloudflare expose a /cdn-cgi/trace path whose sni= line reads plaintext or encrypted. That describes your connection, not a capability.
  4. 4Otherwise capture the handshake and read server_name in the ClientHello. A cover name means ECH is live; the site's own hostname means it is not.
  5. 5Do not read the presence of an ECH extension as proof — browsers deliberately send decoy ones on ordinary connections. The name field is the evidence.

Browser behavior, and the setting people ask about

“Should I enable ECH in Firefox” is usually the wrong question, because it is already on. Firefox ships with ECH enabled and exposes it as network.dns.echconfig.enabled in about:config, but toggling that changes nothing where the site publishes no key. Chromium ships it enabled with no user-facing switch at all: the chrome://flags entry was retired after Chrome 121, and the only supported control left is an enterprise policy. Safari is the outlier: Apple's stack carries the code and offers it to apps, but Safari does not turn it on for ordinary browsing and exposes nothing to flip. Elsewhere the browser is rarely the binding constraint; the site's provider and your DNS path are.

For most people the setting worth changing is encrypted DNS, not ECH: it is the link most often missing, and sometimes the one that lets ECH engage.

Does ECH hide my browsing from my internet provider?

It hides which hostname you requested, not the address you connected to, when, or how much data moved. Behind a large shared front end the address is ambiguous, so the hostname was the informative part; a site on its own address is identified by that address anyway.

Is ECH on by default?

In the browser, generally yes. On any given connection, often no. Firefox and Chromium-based browsers enable it, Safari does not, and it engages only when the site's provider publishes a key in DNS and the browser receives it. Many sites publish nothing, and those connections carry the hostname in plain text.

What is the difference between ECH and ESNI?

ESNI was an earlier, abandoned design that encrypted only the hostname field using a key in a DNS TXT record. ECH encrypts the whole ClientHello and takes its key from an HTTPS record. Two designs, not two names for one thing.

Do I still need encrypted DNS if ECH is working?

Yes. ECH protects the name inside the handshake; a plaintext lookup exposes the same name a moment earlier. Some browsers use ECH regardless of how the record was fetched, so a connection can have ECH active and still have disclosed its hostname over DNS.

Does ECH help when I am already using a VPN?

Not between your device and the exit, since the tunnel already covers that segment. It applies from the exit onward, replacing the site's hostname with a cover name. The destination address stays visible there regardless.

Did this help?

Nothing follows from the answer; only we see it.

Send this to someone

Useful to anyone with the same problem.