XTLS/Xray-core · warning
failed to set PROXY protocol v${xver}
Error message
failed to set PROXY protocol v${xver} What it means
Writing the synthesized PROXY protocol header (v1 text or v2 binary depending on fb.Xver) to the fallback connection failed on its first WriteMultiBuffer. The header carries the original client's addresses so the backend sees the real source IP.
Source
Thrown at proxy/trojan/server.go:523
if ipType == 0 {
common.Must2(pro.Write([]byte("\x20\x00\x00\x00"))) // v2 + LOCAL + UNSPEC + UNSPEC + 0 bytes
break
}
if ipType == 4 {
common.Must2(pro.Write([]byte("\x21\x11\x00\x0C"))) // v2 + PROXY + AF_INET + STREAM + 12 bytes
common.Must2(pro.Write(net.ParseIP(remoteAddr).To4()))
common.Must2(pro.Write(net.ParseIP(localAddr).To4()))
} else {
common.Must2(pro.Write([]byte("\x21\x21\x00\x24"))) // v2 + PROXY + AF_INET6 + STREAM + 36 bytes
common.Must2(pro.Write(net.ParseIP(remoteAddr).To16()))
common.Must2(pro.Write(net.ParseIP(localAddr).To16()))
}
p1, _ := strconv.ParseUint(remotePort, 10, 16)
p2, _ := strconv.ParseUint(localPort, 10, 16)
common.Must2(pro.Write([]byte{byte(p1 >> 8), byte(p1), byte(p2 >> 8), byte(p2)}))
}
if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {
return errors.New("failed to set PROXY protocol v", fb.Xver).Base(err).AtWarning()
}
}
if err := buf.Copy(reader, serverWriter, buf.UpdateActivity(timer)); err != nil {
return errors.New("failed to fallback request payload").Base(err).AtInfo()
}
return nil
}
writer := buf.NewWriter(connection)
getResponse := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
if err := buf.Copy(serverReader, writer, buf.UpdateActivity(timer)); err != nil {
return errors.New("failed to deliver response payload").Base(err).AtInfo()
}
return nil
}
View on GitHub (pinned to 7d214f8b09)
Solutions
- Match fb.Xver with the backend: 0 if the backend does not speak PROXY protocol, 1 or 2 only if the listener is configured for proxy_protocol
- On nginx: 'listen 8080 proxy_protocol;' and set_real_ip_from for the xray host
- Check backend logs for the reason it closed right after accept
Example fix
// json trojan fallback with PROXY v2 for a backend that supports it
"fallbacks": [{"dest": 8080, "xver": 2}]
# nginx:
# listen 127.0.0.1:8080 proxy_protocol;
# set_real_ip_from 127.0.0.1; Defensive patterns
Strategy: validation
Validate before calling
// pick xver by backend capability, not by preference
func proxyProtoVer(backendSupportsProxyProto bool) int {
if !backendSupportsProxyProto { return 0 }
return 2 // v2 unless the backend only parses v1
} Try / catch
if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {
// backend rejected/closed on PROXY header: mismatch between xver and listener
return errors.New("failed to set PROXY protocol v", fb.Xver).Base(err).AtWarning()
} Prevention
- Set xver=0 unless the backend listener is explicitly proxy_protocol-enabled
- On nginx pair xver:2 with 'listen ... proxy_protocol' plus set_real_ip_from
- Document which fallback dests speak PROXY protocol directly in the config file
When it happens
Trigger: The fallback backend closed the connection immediately after accept (it does not understand PROXY protocol and resets), or the socket broke between the successful dial and this first write.
Common situations: xver is set to 1/2 but the backend (e.g. plain nginx http block without proxy_protocol listener) does not expect it, causing instant close; backend has proxy-protocol validation that rejects the header.
Related errors
- Trojan fallbacks: invalid PROXY protocol version, "xver" onl
- Trojan fallbacks: "path" must be empty or start with "/"
- Trojan fallbacks: please fill in a valid value for every "de
- failed to find the default "name" config
- failed to find the default "alpn" config
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/64d51878891a4ccb.
Report an issue: GitHub.