Trojan Rust

Transports

Pluggable transport options for relay hops

Each relay hop can independently use a different transport. The transport is configured per-node in the chain definition and communicated via handshake metadata.

Available Transports

TransportDescriptionUse Case
tlsTLS 1.2/1.3 encryptionPublic internet hops
plainRaw TCP (no encryption)Trusted networks, localhost, WireGuard tunnels

Configuring Transports

In Chain Nodes (Entry Node)

[chains.example]
nodes = [
  # First hop: TLS with custom SNI
  { addr = "relay-1.example.com:443", password = "pw1", transport = "tls", sni = "cdn.example.com" },
  # Second hop: plain TCP (trusted network)
  { addr = "relay-2.internal:8080", password = "pw2", transport = "plain" },
]

In Relay Node (Inbound)

[relay]
listen = "0.0.0.0:443"
transport = "tls"        # What this relay accepts

TLS Transport

  • Auto-generates self-signed ECDSA P-256 certificates at startup
  • Certificate verification is skipped between relay nodes
  • SNI can be configured per-hop to disguise traffic
  • Optionally load certificates from files:
[relay.tls]
cert = "/path/to/cert.pem"
key = "/path/to/key.pem"

Plain TCP Transport

  • Zero overhead, no encryption
  • Use only on trusted networks (localhost, VPN, WireGuard)
  • The last hop to the exit server always uses plain TCP (client handles end-to-end TLS)

Transport Selection Logic

The entry node determines the transport for each hop:

  1. First hop: Uses the transport specified in chain.nodes[0].transport
  2. Intermediate hops: The handshake metadata tells the relay which transport to use for the outbound connection
  3. Last hop (to exit server): Always plain TCP
A ──TLS──▶ B1 ──plain──▶ B2 ──plain──▶ C(trojan-server)


Client ────────────── end-to-end TLS ────┘

On this page