Skip to content

TUN — Xray-core

Xray-core ships a TUN inbound at proxy/tun. It creates a TUN device, reads raw packets, and decodes them with a minimal in-process network stack before dispatching to outbounds. Historically you had to set up routes, DNS, and firewall rules yourself; recent builds add opt-in helpers — gateway, dns, autoSystemRoutingTable, and autoOutboundsInterface — that let Xray install system routing-table entries and bind outbounds to a physical interface automatically.

It is still lighter-weight than the sing-box / mihomo TUN stacks: there is no strict-route, auto-redirect, or UID/package filtering. For those, use sing-box or mihomo as a TUN front-end and route their outbound through Xray.

Inbound

settings for "protocol": "tun":

FieldTypeDefaultAllowed valuesDescription
namestringxray0<interface name>Name of the TUN device. Created at startup.
mtuuint321500<bytes>Maximum transmission unit for the device.
gateway[]string<ip address> | …Gateway address(es) assigned to the TUN interface.
dns[]string<ip address> | …DNS server address(es) configured on the TUN interface.
userLeveluint320<uint32>Default policy level for connections received on this inbound.
autoSystemRoutingTable[]string<routing-table entry> | …When set, Xray automatically installs system routing-table entries that steer traffic into the device. Supplying this list enables auto-routing.
autoOutboundsInterface*stringauto<interface name> | autoPhysical interface that outbound connections bind to, preventing routing loops. Defaults to "auto" when autoSystemRoutingTable is set.

Source: infra/conf/tun.go:8-16 · pinned at v26.6.1 (94ffd50)

Example

json
{
  "inbounds": [{
    "tag": "tun-in",
    "protocol": "tun",
    "settings": {
      "name": "xray0",
      "mtu": 9000
    }
  }]
}

To let Xray manage routing itself, add autoSystemRoutingTable (and optionally pin the outbound interface):

json
{
  "inbounds": [{
    "tag": "tun-in",
    "protocol": "tun",
    "settings": {
      "name": "xray0",
      "mtu": 1500,
      "autoSystemRoutingTable": ["main"],
      "autoOutboundsInterface": "auto"
    }
  }]
}

Or configure the system networking manually instead:

sh
# Linux example
ip addr add 198.18.0.1/30 dev xray0
ip link set xray0 up

# Route everything through xray0 (skip your management subnet)
ip route add 1/1 dev xray0
ip route add 128/1 dev xray0

# DNS hijack
iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-port 5353
# (then have an Xray dokodemo-door inbound on 5353)

Notes

  • Xray's TUN inbound is a low-level packet reader. It does not parse TCP/IP itself; instead, packets are decoded by a minimal in-process network stack and dispatched to outbounds.
  • Common usage on Linux: pair with dokodemo-door inbounds and a hand-crafted iptables ruleset for the transparent-proxy parts, or set autoSystemRoutingTable to have Xray install the routes itself.
  • autoSystemRoutingTable makes Xray manage system routing-table entries automatically; when it is present and autoOutboundsInterface is omitted, the outbound interface defaults to auto. gateway and dns set the address and resolver(s) on the device.
  • On Windows/macOS, the Xray TUN inbound creates a wintun / utun device. With autoSystemRoutingTable it can wire up routing for you; otherwise script it yourself. Many users on those platforms still prefer sing-box or mihomo for the richer TUN feature set.

Cross-core notes

  • sing-box has a feature-complete TUN inbound with auto_route, auto_redirect, strict_route, route_address, UID/package filtering, and per-platform stack choice (gVisor / system / mixed). See TUN — sing-box.
  • mihomo has an equivalent feature-complete TUN inbound at the top-level tun: block with the same option set under kebab-case names. See TUN — mihomo.

Source: infra/conf/tun.go:8-16 · v26.6.1 (94ffd50)

Core Tutorial by Argsment