VLESS — Xray-core
VLESS is Xray's stateless flagship protocol. There is no symmetric cipher inside the protocol itself; confidentiality and integrity come from the outer TLS / REALITY layer. The handshake carries a UUID for the user and a small "addons" block (notably the flow algorithm).
Inbound
settings for an inbound of "protocol": "vless":
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
users | []json.RawMessage | — | <user object array> | … | Inbound account list; same object shape as `clients`. `users` is the newer name introduced in recent Xray and is accepted alongside `clients`. |
clients | []json.RawMessage | (required) | <user object array> | List of accepted users. Each entry carries at minimum `id` (UUID) and optionally `email`, `level`, `flow`, `testseed`, `reverse`. Setting `encryption` on an inbound client is rejected. |
decryption | string | (required) | none | mlkem768x25519plus.<mode>.<seconds>.<keys> | Must be explicitly set. `none` is the classic VLESS no-crypto mode. The mlkem-based string enables the new post-quantum encryption — see Notes below for the format. |
fallbacks | []*VLessInboundFallback | [] | <VLessInboundFallback array> | Fallback destinations consulted when the incoming TLS-with-VLESS handshake does not look like VLESS (e.g. a stray HTTPS request). Mutually exclusive with non-`none` `decryption`. |
flow | string | (empty) | | xtls-rprx-vision | Default flow applied to clients that do not set their own. `xtls-rprx-vision` enables XTLS Vision; empty disables flow. |
testseed | []uint32 | [] | <uint32 array> | Seed values used by the deterministic-test mode of the encryption suite. Almost always omitted. |
Source: infra/conf/vless.go:33-40 · pinned at v26.6.1 (94ffd50)
clients[] — user object
The user object is JSON-decoded into the protobuf-backed vless.Account struct. The fields you care about:
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
id | string (UUID) | required | <UUID> | Client UUID. Canonical 8-4-4-4-12 or dash-less hex. |
email | string | "" | <string> | Tag used in stats/log output. |
level | uint32 | 0 | <level> | Looked up in policy.levels. |
flow | string | inherits flow | "", xtls-rprx-vision | Per-user flow override. |
testseed | []uint32 | inherits | — | Per-user test-seed override. |
encryption | string | forbidden | — | Not allowed on inbound clients. |
reverse | {tag,sniffing?} | (unset) | VLessReverseConfig | Bind this user to a reverse-proxy tag. sniffing is not allowed inside an inbound's reverse block. |
fallbacks[]
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
name | string | (unset) | <TLS server name> | Match incoming TLS SNI; empty matches any. |
alpn | string | (unset) | h2 | http/1.1 | | Match the negotiated ALPN; empty matches any. |
path | string | (unset) | /<path> | HTTP path prefix used when proxying. Must start with `/` if non-empty. |
type | string | (auto) | tcp | unix | serve | Backend protocol. Inferred from `dest` when omitted: numeric port or host:port → tcp; absolute / @-prefixed path → unix; `serve-ws-none` → serve. |
dest | json.RawMessage | (required) | <host:port> | <port> | <unix path> | Where to forward the handshake. A bare integer is treated as a port on localhost. |
xver | uint64 | 0 | 0 | 1 | 2 | PROXY-protocol version to prepend to the forwarded connection. 0 disables. |
Source: infra/conf/vless.go:24-31 · pinned at v26.6.1 (94ffd50)
The fallback chain runs in declaration order on the first byte of the incoming connection when it does not look like VLESS. Field ordering matters: matches are tested by (name, alpn, path) tuples, and the first match wins. See infra/conf/vless.go:149-200 for the parsing of dest.
Outbound
settings for an outbound of "protocol": "vless":
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
address | *Address | (unset) | <host> | Simplified shape — server hostname or IP. When set, `vnext` is constructed internally and the top-level `id`, `flow`, etc. are read directly. |
port | uint16 | (required with address) | <port> | Server port (simplified shape). |
level | uint32 | 0 | <uint32> | User level (simplified shape) — keyed into the policy table. |
email | string | (unset) | <string> | User identifier reported in stats. |
id | string | (required with address) | <UUID> | User UUID (simplified shape). Accepts both canonical and dash-less hex. |
flow | string | (empty) | | xtls-rprx-vision | xtls-rprx-vision-udp443 | Flow algorithm. |
seed | string | (unset) | <string> | Encryption seed (reserved). Currently parsed but not applied — kept for forward compat. |
encryption | string | (required) | none | mlkem768x25519plus.<mode>.<rtt>.<keys> | Must be set to `none` or the mlkem encryption string. Anything else is rejected. |
reverse | *VLessReverseConfig | (unset) | VLessReverseConfig | Optional reverse-proxy tag binding for outbound-side reverse tunnels. |
testpre | uint32 | 0 | <uint32> | Pre-test counter for the deterministic test mode. |
testseed | []uint32 | [] | <uint32 array> | Seed values for the deterministic test mode. |
vnext | []*VLessOutboundVnext | (use simplified shape) | [{address,port,users:[user]}] | Verbose shape — must hold exactly one server with exactly one user. Use one outbound per server and a balancer if you want multiple endpoints. |
Source: infra/conf/vless.go:245-258 · pinned at v26.6.1 (94ffd50)
Simplified vs. vnext
The outbound accepts either the simplified top-level shape (address, port, id, flow, ...) or the verbose vnext shape — never both. The simplified form is rewritten into a single-entry vnext array internally (infra/conf/vless.go:251-259). The verbose form must contain exactly one server with exactly one user; for multi-server setups, use multiple VLESS outbounds and a routing balancer.
Examples
Minimal inbound with a single user and XTLS Vision:
{
"inbounds": [
{
"tag": "vless-in",
"listen": "0.0.0.0",
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{ "id": "a3482e88-686a-4a58-8126-99c9df64b7bf", "flow": "xtls-rprx-vision" }
],
"decryption": "none"
},
"streamSettings": { "network": "tcp", "security": "tls" }
}
]
}Simplified outbound:
{
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"address": "example.com",
"port": 443,
"id": "a3482e88-686a-4a58-8126-99c9df64b7bf",
"flow": "xtls-rprx-vision",
"encryption": "none"
},
"streamSettings": { "network": "tcp", "security": "reality", "realitySettings": { /* ... */ } }
}
]
}Notes
decryptionandencryptionare required. Omitting them produces the errorplease add/set "decryption":"none" to every settings(infra/conf/vless.go:140) or the matching outbound error.- The mlkem-based encryption string is parsed by the inline closure in
Build(infra/conf/vless.go:95-137inbound,321-357outbound). Format:mlkem768x25519plus.<mode>.<seconds-or-rtt>.<keys-and-padding>where mode isnative,xorpub, orrandom; seconds is<from>or<from>-<to>(inbound) or1rtt/0rtt(outbound); keys are base64-url-safe 32-byte or 1184-byte values, with short strings used as padding. - The only flow value accepted in current source is
xtls-rprx-vision, with the outbound additionally accepting the-udp443suffix. fallbackscannot be combined with a non-nonedecryption(infra/conf/vless.go:145-147).fallbacks[].xver > 2is rejected. Only PROXY protocol v0/v1/v2 are accepted.
Cross-core notes
- sing-box uses
users[].uuidinstead of Xray'sclients[].id, andusers[].nameinstead ofemail. See VLESS — sing-box. - mihomo has a single outbound shape (no inbound/outbound asymmetry in the YAML); user UUIDs are stored on the proxy object itself rather than in a clients array. See VLESS — mihomo.
Source: infra/conf/vless.go:24-258 · v26.6.1 (94ffd50)
