{"record":{"id":"0071797880095b57","repo":"XTLS/Xray-core","slug":"outbound-interface-cannot-be-the-tun-interface-007179","errorCode":null,"errorMessage":"outbound interface cannot be the TUN interface","messagePattern":"outbound interface cannot be the TUN interface","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/tun/tun_linux.go","lineNumber":346,"sourceCode":"\t\t\t\treturn\n\t\t\t}\n\t\t\tif updater != nil {\n\t\t\t\tupdater.Update()\n\t\t\t}\n\t\tcase <-t.routeMonitorStop:\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc findOutboundInterface(tunIndex int, fixedName string) (*net.Interface, error) {\n\tif fixedName != \"\" {\n\t\tiface, err := net.InterfaceByName(fixedName)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif iface.Index == tunIndex {\n\t\t\treturn nil, errors.New(\"outbound interface cannot be the TUN interface\")\n\t\t}\n\t\treturn iface, nil\n\t}\n\n\tfor _, family := range []int{\n\t\tnetlink.FAMILY_V4,\n\t\tnetlink.FAMILY_V6,\n\t} {\n\t\tiface, err := findDefaultInterface(family, tunIndex)\n\t\tif err == nil {\n\t\t\treturn iface, nil\n\t\t}\n\t}\n\n\treturn nil, errors.New(\"no usable outbound interface found\")\n}\n\nfunc findDefaultInterface(family int, tunIndex int) (*net.Interface, error) {","sourceCodeStart":328,"sourceCodeEnd":364,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/tun/tun_linux.go#L328-L364","documentation":"When a fixed outbound interface is configured for the tun proxy, Xray verifies it is not the TUN interface itself. Binding outbound traffic to the TUN would create a routing loop (packets re-entering the tunnel). The check compares the resolved interface index against the TUN link index and fails on equality.","triggerScenarios":"Configuring the tun inbound's \"interface\"/outbound bind setting to the same name as the TUN device (e.g. both \"tun0\"); wildcard or guessed names that happen to resolve to the TUN.","commonSituations":"Copy-pasted configs where someone set interface to the only NIC they see, which is the freshly created TUN; renaming the physical NIC so an old name now matches the TUN.","solutions":["Point the fixed interface at the physical NIC (e.g. \"eth0\", \"wlan0\") instead of the TUN name","Remove the fixed interface setting to let Xray auto-detect the default-route interface","Verify with `ip link` which name belongs to the physical adapter"],"exampleFix":"// before\n\"interface\": \"tun0\"\n\n// after\n\"interface\": \"eth0\"","handlingStrategy":"validation","validationCode":"if cfg.OutboundInterface != \"\" {\n\tiface, err := net.InterfaceByName(cfg.OutboundInterface)\n\tif err != nil { log.Fatalf(\"unknown interface %q\", cfg.OutboundInterface) }\n\tif iface.Name == cfg.TunName {\n\t\tlog.Fatal(\"outbound interface must not be the TUN interface\")\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Name the outbound interface after the physical NIC (eth0/wlan0)","Omit the setting to use auto-detection","Re-check interface names after renaming NICs or switching Wi-Fi/Ethernet"],"tags":["tun","linux","routing","config","routing-loop"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}