Guide: how Reality (XTLS) works and why it bypasses DPI

There are dozens of Reality configurations on the forum, but few explain why it actually works. And understanding this matters: when you know the mechanics, you consciously tune the dest/serverNames, not just copy someone else’s JSON at random. Let’s break down the REALITY (XTLS) protocol in human terms — no fluff, but to the point.

The problem Reality solves

Classic “TLS-wrappers” (Trojan, VMess+TLS) are vulnerable from several angles:

  • TLS-in-TLS. Inside your TLS, another TLS travels from the proxy — DPI can recognize this “double” pattern.
  • Your certificate = your fingerprint. To run a legitimate TLS, you need a domain and a certificate, and the combo “domain + certificate + server behavior” forms an identifiable signature.
  • SNI is visible. The domain name in ClientHello is open — censors can easily block by SNI.
  • Active probes. A censor hits your server and, based on an non-standard response, realizes it’s a proxy.

The key idea: not to set up TLS, but to borrow someone else’s

Reality does not implement its own TLS — it borrows the handshake from a real third-party site. In the config you specify the real target (dest, for example www.microsoft.com:443), and the client makes it look like it’s connecting to that site. From the outside it appears as a regular visit to a popular site with a valid certificate for that site.

Next comes authentication with X25519:

  • the server generates an X25519 key pair; the public key is effectively the client password (publicKey);
  • the client, inside a legitimate TLS stream, proves knowledge of the key — covertly to an observer;
  • authenticated client obtains a temporary certificate signed by an ephemeral key, and continues to ride the proxy;
  • unauthenticated request (censor probe, random scanner) fails against the real target site and gets its real content.

That’s the magic: the server is indistinguishable from the site it impersonates. If it doesn’t have its own certificate — there’s nothing to fingerprint; no TLS-in-TLS — nothing to catch; an active probe bounces off the real microsoft.com.

The main config parameters

From the server side:

  • dest (target) — the real site donor of the handshake, domain:port;
  • serverNames — list of SNI that the client is allowed to present (must correspond to dest);
  • privateKey — the private key for X25519;
  • shortIds — short identifiers for differentiating clients/groups.

From the client side:

  • serverName — which SNI to present (from serverNames);
  • publicKey — the server’s public key;
  • shortId — corresponding identifier;
  • fingerprint — uTLS profile (chrome, firefox, etc.) so that the TLS fingerprint matches real browser traffic.

A sober assessment: not a silver bullet

Reality is strong, but it has rigid requirements that trip up beginners.

  • Choosing dest is critical. The donor should be a “foreign”, popular site that supports TLS 1.3 and X25519, geographically close to your server, and not behind Cloudflare or your own host. A bad dest — masking collapses.
  • serverNames must match dest. Desynchronization is the typical reason for “not connecting.”
  • This is not a cure-all for blocks. Reality masks the fingerprint, but does not shield from IP-based blocking of your server or from traffic volume/timeing heuristics. Fresh blocks sometimes require combining transports (see forum topic about xHTTP).
  • Compatibility. Reality is part of the XTLS/Xray ecosystem; both client and server must support it (current Xray-core, sing-box, clients like v2rayN/Throne/Streisand).

What to do

  1. Choose dest consciously: a large third-party site with TLS 1.3 and X25519, geographically near your server, not behind Cloudflare. You can verify support, for example, via online TLS checkers.
  2. Keep serverName = one of the serverNames = the dest domain. This fixes about 90% of the “not connecting” issues.
  3. Set fingerprint: chrome (or the current browser profile) on the client — so the uTLS fingerprint matches the mass of traffic.
  4. Don’t rely solely on Reality: with strong DPI, keep a backup transport and remember about IP-based blocks.

Sources

Which dest are you using and what criteria did you use to select it? And have you noticed any degradation of Reality under recent DPI — what helped: changing the donor, IP, or combining transports?