Skip to main content

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:

FieldTypeDescription
namestringUser-chosen node name. Must be unique inside the config file.
typestringMust be exactly "VlessServer".
settingsobjectNon-empty VLESS server settings.
nextstringRequired. 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.

FieldTypeDescription
uuidstringOne UUID.
idstringAlias for uuid. Use either uuid or id, not both.
uuidsarray of stringsMultiple UUIDs.
usersarrayUUID strings or objects with one of uuid, id, or user-id. Objects can include username.
clientsarrayAlias 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

FieldTypeDescription
auth-client-node-namestringName of an existing AuthenticationClient node in the same config.

In database mode, do not configure uuid, id, uuids, users, or clients.

Optional Settings

FieldDefaultDescription
connecttrueEnables VLESS TCP command 0x01.
udptrueEnables VLESS UDP command 0x02.
verbosefalseEnables extra rejection and diagnostic logging.
fallback-node-namenot setFallback branch for unauthenticated invalid probes. Aliases: fallback-node, fallback.
fallback-intentional-delay-ms7Delay for upstream payloads sent to fallback. Set 0 to disable.
fallback-intentional-delay-jitter-ms1Random 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:

  1. authenticates the UUID
  2. parses the requested destination
  3. writes that destination into line->routing_context.dest_ctx
  4. initializes the configured next node
  5. forwards any TCP body bytes that arrived in the same payload as the request header
  6. 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
  • AuthenticationClient not being ready

When fallback is configured:

  • the fallback branch receives Init immediately
  • saved initial bytes and later upstream payloads are forwarded to fallback
  • upstream fallback payloads can be delayed by fallback-intentional-delay-ms plus jitter
  • an upstream Finish waits 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

PropertyValue
Node flagkNodeFlagChainHead
Previous nodeAllowed, required in normal use
Next nodeRequired
Layer groupkNodeLayerAnything
required_padding_left2
Line stateauth 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 VlessServer directly on a public TCP listener without TlsServer unless 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 internal UserController.
  • 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.