Trojan — Xray-core
Trojan is a TLS-shaped tunnel with a password handshake. In Xray-core the implementation matches the original Trojan spec and does not support the XTLS flow extension — the flow field is still parsed for compatibility but any non-empty value produces a hard error (infra/conf/trojan.go:73, 128).
Outbound
settings for an outbound of "protocol": "trojan":
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
address | *Address | (unset) | <host> | Simplified shape — server hostname or IP. |
port | uint16 | (required with address) | <port> | Server port. |
level | byte | 0 | <byte> | User level (simplified shape). |
email | string | (unset) | <string> | User identifier reported in stats. |
password | string | (required with address) | <string> | Shared password for the Trojan handshake. |
flow | string | (must be empty) | — | Removed feature. Setting any non-empty value rejects the config at startup. |
servers | []*TrojanServerTarget | (use simplified shape) | [TrojanServerTarget] | Verbose shape. Must hold exactly one server; multiple servers require multiple outbounds + a balancer. |
Source: infra/conf/trojan.go:31-39 · pinned at v26.6.1 (94ffd50)
servers[]
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
address | *Address | (required) | <host> | Server hostname or IP. |
port | uint16 | (required) | <port> | Server port. |
level | byte | 0 | <byte> | User level. |
email | string | (unset) | <string> | User identifier. |
password | string | (required) | <string> | Trojan password. |
flow | string | (must be empty) | — | Removed; non-empty value is rejected. |
Source: infra/conf/trojan.go:21-28 · pinned at v26.6.1 (94ffd50)
Simplified vs. servers
The outbound accepts either the simplified top-level shape (address, port, password, ...) or the verbose servers shape with exactly one entry. For multi-server setups use multiple Trojan outbounds plus a routing balancer.
Inbound
settings for an inbound of "protocol": "trojan":
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
users | []*TrojanUserConfig | — | [TrojanUserConfig] | … | Inbound account list; same object shape as `clients`. `users` is the newer name introduced in recent Xray and is accepted alongside `clients`. |
clients | []*TrojanUserConfig | (required) | [TrojanUserConfig] | List of accepted users. |
fallbacks | []*TrojanInboundFallback | [] | [TrojanInboundFallback] | Fallback destinations consulted when the incoming TLS-wrapped traffic does not look like Trojan. |
Source: infra/conf/trojan.go:114-118 · pinned at v26.6.1 (94ffd50)
clients[]
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
password | string | (required) | <string> | Trojan password. |
level | byte | 0 | <byte> | Policy level for this user. |
email | string | (unset) | <string> | Tag in stats/log output. |
flow | string | (must be empty) | — | Removed; non-empty value is rejected. |
Source: infra/conf/trojan.go:106-111 · pinned at v26.6.1 (94ffd50)
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. Must start with `/` if non-empty. |
type | string | (auto) | tcp | unix | serve | Backend protocol. Inferred from `dest` when omitted. |
dest | json.RawMessage | (required) | <host:port> | <port> | <unix path> | Forwarding target. Bare integer = port on localhost. |
xver | uint64 | 0 | 0 | 1 | 2 | PROXY-protocol version. 0 disables. |
Source: infra/conf/trojan.go:96-103 · pinned at v26.6.1 (94ffd50)
The Trojan fallback chain mirrors VLESS: matched in order on the first byte of the TLS-wrapped stream, with (name, alpn, path) as the keys.
Examples
Minimal inbound with one user and TLS:
{
"inbounds": [
{
"tag": "trojan-in",
"listen": "0.0.0.0",
"port": 443,
"protocol": "trojan",
"settings": {
"clients": [
{ "password": "<password>", "email": "alice" }
]
},
"streamSettings": { "network": "tcp", "security": "tls" }
}
]
}Simplified outbound:
{
"outbounds": [
{
"tag": "trojan-out",
"protocol": "trojan",
"settings": {
"address": "example.com",
"port": 443,
"password": "<password>",
"email": "alice"
},
"streamSettings": {
"network": "ws",
"security": "tls",
"wsSettings": { "path": "/tj" }
}
}
]
}Notes
flowon Trojan is a removed feature in Xray-core. The struct field still exists for backwards-compatible parsing, but supplying any non-empty value triggersPrintRemovedFeatureError("Flow for Trojan")at startup. The runtime also prints a deprecation banner recommending "VLESS with Flow & Seed" (infra/conf/trojan.go:42, 120).passwordis required. An outbound with empty password fails to build (infra/conf/trojan.go:69-71).fallbackswork exactly like VLESS fallbacks — same field shape and same auto-inference fortypefromdest.
Cross-core notes
- sing-box uses
users[](withname/password) instead ofclients[], and replaces Xray's fallback chain with two distinct options: a singlefallbacktarget plusfallback_for_alpnkeyed by ALPN. See Trojan — sing-box. - mihomo has the standard single-proxy-object outbound shape, and also exposes a Shadowsocks-over-Trojan (
ss-opts) compatibility layer for trojan-go clients. See Trojan — mihomo.
Source: infra/conf/trojan.go:21-118 · v26.6.1 (94ffd50)
