Search for a sing-box Reality guide and you will find a lot of configuration files that were correct in 2024. They still parse, which is the problem: nothing warns you that you have just built on fields the project deprecated. This walks through a VLESS Reality setup checked field by field against the current documentation, and flags the parts that have quietly moved.
For reference, the version this was checked against is sing-box 1.13.15, released on 29 July 2026.
What Reality actually changes
Conventional TLS-based proxies have a structural weakness: the certificate belongs to you. A censor who inspects the handshake sees a domain and a certificate that do not correspond to a real, popular website, and that mismatch is itself the signal.
Reality's approach is to borrow the handshake of a genuine third-party site. Your server is configured to point at a real external host, and traffic that fails authentication is passed through to it. To an observer, the connection resembles a connection to that site, because in part it is.
This is why the configuration has a handshake block. It is not decoration and its choice matters more than any other value you will set.
The three required Reality fields on the server
Inside the tls object, the reality block requires exactly three things according to the documentation:
handshake(object), containingserverandserver_port, the external site your server borrows fromprivate_key(string), which the documentation says is generated bysing-box generate reality-keypairshort_id(string), described as a hexadecimal string with zero to eight digits
There is also an enabled boolean, and an optional max_time_difference, which sets the tolerated clock difference between the two ends. The documentation notes that the check is disabled when this is left empty. If you do set it, keep in mind that you are now dependent on both machines keeping accurate time.
Generating the keys
Two values need generating before you write anything:
sing-box generate reality-keypair
sing-box generate uuid
The keypair prints a private key and a public key. The private key stays on the server. The public key goes to every client. The UUID is the VLESS user identity.
Keep the pair together somewhere safe when you generate it. The public key is not recoverable from a config file that only stores the private one, and regenerating the pair invalidates every client you have already handed out.

The server inbound
A VLESS inbound requires type, tag, the listen fields, and a users array. Each user entry takes a uuid, optionally a name, and optionally a flow. The documentation lists exactly one available flow value: xtls-rprx-vision.
{
"type": "vless",
"tag": "vless-in",
"listen": "::",
"listen_port": 443,
"users": [
{
"name": "me",
"uuid": "PASTE-YOUR-GENERATED-UUID",
"flow": "xtls-rprx-vision"
}
],
"tls": {
"enabled": true,
"server_name": "your-handshake-host.example",
"reality": {
"enabled": true,
"handshake": {
"server": "your-handshake-host.example",
"server_port": 443
},
"private_key": "PASTE-YOUR-PRIVATE-KEY",
"short_id": "0123abcd"
}
}
}
Note server_name and the handshake server. These are separate fields that will normally hold the same host, and a mismatch between them is a common cause of a setup that builds fine and then fails at connection time.
The part most guides get wrong
Here is the difference between a 2024 config and a current one. These three inbound fields were deprecated in version 1.11.0:
sniffsniff_timeoutdomain_strategy
They moved out of the inbound and became route rule actions. The migration guide gives the direct equivalents:
{
"route": {
"rules": [
{ "inbound": "vless-in", "action": "sniff", "timeout": "1s" },
{ "inbound": "vless-in", "action": "resolve", "strategy": "prefer_ipv4" }
]
}
}
So "sniff": true becomes an action of sniff, sniff_timeout becomes that action's timeout, and domain_strategy becomes an action of resolve with a strategy.
To be accurate about the stakes: the documentation marks these as deprecated and does not announce a removal date. Nothing breaks today. But a config that still carries them is written against an interface the project has moved away from, and that is worth knowing when you are choosing which tutorial to follow.
Two related fields, sniff_override_destination and udp_disable_domain_unmapping, are also marked deprecated in the current listen field documentation.
The client side
The client needs less than the server. Reality on the client requires:
public_key, the counterpart to the server's private keyshort_id, which must match a value the server accepts
The utls object sits alongside it, with enabled and fingerprint. Accepted fingerprint values documented are chrome, firefox, edge, safari, 360, qq, ios, android, random and randomized. The documentation states that the Chrome fingerprint is used when the field is empty.
One point of honesty here, because guides tend to assert the opposite: the sing-box documentation presents utls as an independent TLS option and does not state that Reality requires it. Most client configs enable it regardless.
Choosing the handshake host
No config value affects your outcome more, and no guide can pick it for you, because the right answer depends on where your server is and where your clients are.
The properties that matter:
- It should be a host that genuinely supports TLS 1.3 on the port you point at
- It should be plausible traffic from your server's network location
- It should not be a site that is itself blocked in the country you are connecting from, which would defeat the purpose entirely
- It should not be a site you control, since the point is that it is somebody else's real traffic
A frequently repeated piece of advice is to pick something large and generic. Be careful with that reasoning: a host that every tutorial recommends is, by definition, a host that appears in every config, and popularity within the proxy community is not the same thing as blending in.
Before you conclude it works
Two checks worth doing that go beyond "the client connected".
Confirm the fallback behaves. Point a plain browser at your server's address and port. What you should see is the handshake site, not an error and not a timeout. If you get something else, the passthrough is not doing its job and the setup is more conspicuous than an ordinary proxy.
Check both clocks. If you set max_time_difference, drift on either machine will produce failures that look like authentication problems and send you editing keys that were never wrong.
If you are still deciding between engines rather than configuring one, the trade-offs are laid out in our sing-box vs Xray comparison.
The short version
Three required Reality fields on the server: handshake, private_key, short_id. Two on the client: public_key, short_id. Keys come from sing-box generate reality-keypair. And if the guide you are reading puts sniff or domain_strategy inside the inbound, it predates version 1.11 and the current equivalent is a route rule action.
Field names, requirements and deprecations in this article were taken from the official sing-box documentation and migration guide, checked against release 1.13.15 on 30 July 2026. Configuration interfaces change between versions, so verify against the documentation for the release you are running. Bypassing censorship is restricted or unlawful in some jurisdictions; check what applies where you are.
★ Nuremberg GDPR datacenter · ✓ Dedicated IPv4 included · 200+ Mbps guaranteed
A VPS you fully control for tunneling & obfuscation → ContaboRoot access · open any port · run your own stack→

