VlessServer
VlessServer is the server-side plain VLESS v0 tunnel for WaterWall. It parses the VLESS request header from the
previous stream-facing node, authenticates the 16-byte raw UUID, extracts the requested TCP or UDP destination, and
forwards accepted traffic to its configured next node.
This node implements only base VLESS protocol handling. It does not create TLS, REALITY, XTLS Vision, mux, reverse, XUDP, or transport-specific wrapping.
Typical Placement
Normal VLESS server:
TcpListener -> TlsServer -> VlessServer -> TcpUdpConnector
TCP-only outbound:
TcpListener -> TlsServer -> VlessServer -> TcpConnector
UDP-capable outbound:
TcpListener -> TlsServer -> VlessServer -> TcpUdpConnector
VlessServer does not terminate TLS by itself. For public VLESS deployments, place TlsServer before it. Without TLS,
the UUID and destination metadata are visible on the wire.
Minimal Example
[
{
"name": "tls-in",
"type": "TlsServer",
"settings": {
"cert-file": "/etc/waterwall/fullchain.pem",
"key-file": "/etc/waterwall/privkey.pem"
},
"next": "vless-server"
},
{
"name": "vless-server",
"type": "VlessServer",
"settings": {
"uuid": "5783a3e7-e373-51cd-8642-c83782b807c5",
"connect": true,
"udp": true,
"verbose": false
},
"next": "outbound"
},
{
"name": "outbound",
"type": "TcpUdpConnector",
"settings": {
"address": "dest_context->address",
"port": "dest_context->port"
}
}
]
Multiple Local Users
{
"name": "vless-server",
"type": "VlessServer",
"settings": {
"users": [
"5783a3e7-e373-51cd-8642-c83782b807c5",
{
"username": "alice",
"id": "11111111-2222-3333-4444-555555555555"
}
],
"connect": true,
"udp": true
},
"next": "outbound"
}
In local allowlist mode, a matching object username is recorded on the line. The canonical lowercase UUID string is
also recorded as the line password so Router rules can match authenticated credentials even without a users database.
AuthenticationClient Mode
{
"name": "vless-server",
"type": "VlessServer",
"settings": {
"auth-client-node-name": "auth-client",
"connect": true,
"udp": true
},
"next": "outbound"
}
In this mode, the wire UUID is converted to canonical lowercase dashed form and authenticated as the user's password
through AuthenticationClient.
Example user database entry:
{
"id": 2001,
"name": "vless-user",
"password": "5783a3e7-e373-51cd-8642-c83782b807c5",
"enabled": true
}
When auth-client-node-name is configured, local UUID settings are rejected. VlessServer internally inserts a
UserController before the configured outbound node so user accounting and user-aware routing can work normally.
Fallback Example
{
"name": "vless-server",
"type": "VlessServer",
"settings": {
"uuid": "5783a3e7-e373-51cd-8642-c83782b807c5",
"fallback-node-name": "fallback-service",
"fallback-intentional-delay-ms": 7,
"fallback-intentional-delay-jitter-ms": 1,
"connect": true,
"udp": true
},
"next": "outbound"
}
Fallback is for active-probing resistance. Invalid unauthenticated traffic can be handed to another configured node instead of being closed immediately.
Required Fields
Top-level fields:
| Field | Type | Description |
|---|---|---|
name | string | User-chosen node name. Must be unique inside the config file. |
type | string | Must be exactly "VlessServer". |
settings | object | Non-empty VLESS server settings. |
next | string | Required. Accepted VLESS traffic is forwarded to this node. |
Choose exactly one authentication mode.
Local Authentication Settings
Use local authentication by omitting auth-client-node-name and configuring at least one UUID.
| Field | Type | Description |
|---|---|---|
uuid | string | One UUID. |
id | string | Alias for uuid. Use either uuid or id, not both. |
uuids | array of strings | Multiple UUIDs. |
users | array | UUID strings or objects with one of uuid, id, or user-id. Objects can include username. |
clients | array | Alias for users. Use either users or clients, not both. |
UUIDs may be dashed RFC4122 strings or compact 32-character hex strings. Duplicate local UUIDs are fatal configuration errors, even if the duplicate entries use different usernames.
Database Authentication Settings
| Field | Type | Description |
|---|---|---|
auth-client-node-name | string | Name of an existing AuthenticationClient node in the same config. |
In database mode, do not configure uuid, id, uuids, users, or clients.
Optional Settings
| Field | Default | Description |
|---|---|---|
connect | true | Enables VLESS TCP command 0x01. |
udp | true | Enables VLESS UDP command 0x02. |
verbose | false | Enables extra rejection and diagnostic logging. |
fallback-node-name | not set | Fallback branch for unauthenticated invalid probes. Aliases: fallback-node, fallback. |
fallback-intentional-delay-ms | 7 | Delay for upstream payloads sent to fallback. Set 0 to disable. |
fallback-intentional-delay-jitter-ms | 1 | Random jitter around delayed fallback payload scheduling. Ignored when delay is 0. |
At least one of connect or udp must be enabled.
Request And Response Format
Accepted request format:
version: 1 byte, must be 00
user id: 16 raw UUID bytes
addons len: 1 byte, must be 00
command: 01 TCP or 02 UDP
destination: port first, then address
body: TCP raw stream or UDP length-prefixed packets
Destination format:
port: 2 bytes big-endian
address type: 01 IPv4, 02 domain, 03 IPv6
address body: IPv4 4 bytes, domain length + bytes, or IPv6 16 bytes
Response header:
00 00
The response header is sent only after the selected upstream path establishes. For TCP, that means the outbound path has established. For UDP, that means the internal backend UDP line has initialized through the next node.
TCP Runtime Behavior
For command 0x01, the server:
- authenticates the UUID
- parses the requested destination
- writes that destination into
line->routing_context.dest_ctx - initializes the configured
nextnode - forwards any TCP body bytes that arrived in the same payload as the request header
- sends the VLESS response header after the selected upstream path establishes
The configured next node is usually TcpConnector, TcpUdpConnector, Router, or another node that understands the
destination context.
UDP Runtime Behavior
For command 0x02, the destination from the initial VLESS request is fixed for that VLESS line. Individual UDP frames do
not carry per-packet addresses.
UDP frames use:
length: 2 bytes big-endian
payload: length bytes
VlessServer creates one internal backend UDP line for the target destination. Incoming VLESS UDP frames are decoded and
forwarded to that backend line. Replies from the backend line are wrapped with the same 2-byte length prefix and sent
downstream to the VLESS client.
UDP frames with length 0 are invalid. UDP input buffering is capped at 1 MiB.
Fallback Behavior
Fallback is used only before successful UUID authentication. Once the UUID is accepted, malformed addons, unsupported commands, malformed destinations, or bad UDP frames close the VLESS line instead of replaying authenticated bytes to fallback.
Fallback can be selected for:
- invalid version byte
- UUID split across the first upstream payload
- failed UUID lookup
AuthenticationClientnot being ready
When fallback is configured:
- the fallback branch receives
Initimmediately - saved initial bytes and later upstream payloads are forwarded to fallback
- upstream fallback payloads can be delayed by
fallback-intentional-delay-msplus jitter - an upstream
Finishwaits until delayed fallback payloads have been delivered - downstream fallback responses are not intentionally delayed
Fallback quality is part of the public fingerprint. A down fallback, generic error, immediate close, mismatched content, or mismatched timing can identify the deployment. Tune delay and jitter against the public behavior you are trying to resemble; they are mitigations, not proof of indistinguishability.
First-Payload Authentication Rule
The complete VLESS credential, meaning the version byte plus the 16-byte raw UUID, must be present in the first upstream payload callback.
If the first payload does not contain the full credential, the line is treated as an invalid unauthenticated probe. With fallback configured, those bytes go to fallback. Without fallback, the line is closed. Later VLESS fields may still arrive across multiple payload callbacks after the UUID is present.
Finish Behavior
VlessServer destroys its own line state before propagating real Finish callbacks.
For TCP and fallback branches, it forwards finish toward the selected branch when appropriate. For UDP, it owns the internal backend UDP line it created and closes it safely when either side closes.
Padding
VlessServer may prepend the 2-byte VLESS UDP length prefix on reply packets, so it advertises:
required_padding_left = 2
Node Metadata
| Property | Value |
|---|---|
| Node flag | kNodeFlagChainHead |
| Previous node | Allowed, required in normal use |
| Next node | Required |
| Layer group | kNodeLayerAnything |
required_padding_left | 2 |
| Line state | auth state, phase, read stream, pending queues, UDP backend line |
Unsupported Features
The current implementation rejects:
- nonzero request addons length
- XTLS Vision flow addons
- mux command
0x03 - reverse command
0x04 - unknown commands
- XUDP and advanced UDP/mux behavior
- VLESS over non-stream transports
Invalid unauthenticated probes may go to fallback. Bad authenticated protocol data closes without writing another VLESS response header.
Common Mistakes
- Do not expose
VlessServerdirectly on a public TCP listener withoutTlsServerunless you intentionally want plain VLESS on the wire. - Do not configure local UUIDs together with
auth-client-node-name. - Do not set the next node to a manual
UserController; database mode inserts its own internalUserController. - Do not expect UDP frames to choose a new destination per packet; the initial VLESS request fixes the UDP target.
- Do not rely on unsupported VLESS features such as Vision, flow, mux, reverse, or XUDP.