TUN mode uses Android's VpnService to create a virtual network adapter that feeds the device's traffic as whole packets into the Xray core built into v2rayNG. The article runs in four steps: first the difference from the default local proxy, then the data path, then the order for enabling and authorizing, and finally three reproducible checks to confirm what is captured, plus the usual pitfalls around background survival and DNS resolution.
How TUN mode differs from the default local proxy
By default v2rayNG only opens two local inbounds: SOCKS on 127.0.0.1:10808 and HTTP on 127.0.0.1:10809. Only apps that read proxy settings (browsers, some download tools) send their requests to those ports; everything else connects directly. Android has no system-wide proxy switch for all apps either — the proxy field in the Wi-Fi advanced options only applies to apps that honour it.
TUN mode takes a different path: v2rayNG requests a virtual network adapter through Android's VpnService, and the system writes the IP packets the device sends into that adapter, so no app has to be configured with a proxy address. Packets read from the adapter go to the built-in tun2socks forwarder, which rebuilds them into TCP connections and UDP sessions and hands them to the Xray core as SOCKS5 for routing.
| Aspect | Default local proxy | TUN mode |
|---|---|---|
| What it captures | Apps that set a proxy themselves | All device IP traffic, filterable per app |
| App-side configuration | Must point to 127.0.0.1:10808 | Not required |
| DNS handling | Resolved by each app | Travels into the core with the traffic and follows the domain resolution strategy |
| Permission | None | Requires system VPN authorization |
| Battery use | Low | Slightly higher, one extra user-space hop |
| Typical use case | Browsers and tools that support proxies | Apps without proxy settings, or when everything must be captured |
The data path: from app to outbound
A single request passes through five stages in TUN mode, and each one can be checked on its own.
The first two stages are handled by the system and the forwarder. Once VpnService brings up the adapter, the default route 0.0.0.0/0 points at it, so connections from apps are written into the TUN as whole packets; tun2socks reads the raw IP packets back out, rebuilds TCP connections and UDP sessions, and hands them to 127.0.0.1:10808 as SOCKS5 (including UDP ASSOCIATE).
The last three stages happen inside the Xray core. A request entering the socks inbound is matched against the routing rules first, which then decide whether it leaves through an outbound proxy or a direct freedom connection. When a domain is resolved to an IP is controlled by the domain resolution strategy in Settings: with IPIfNonMatch the domain is matched against rules first and only resolved if nothing matches, which saves a pointless DNS query; with AsIs matching stays on the domain; with IPOnDemand resolution happens only when an IP rule is hit.
{
"inbounds": [
{ "tag": "socks", "listen": "127.0.0.1", "port": 10808, "protocol": "socks", "settings": { "udp": true } },
{ "tag": "http", "listen": "127.0.0.1", "port": 10809, "protocol": "http" }
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{ "type": "field", "outboundTag": "direct", "ip": ["geoip:private"] },
{ "type": "field", "outboundTag": "direct", "domain": ["geosite:cn"] }
]
}
}
The excerpt above covers the inbound and routing sections; outbounds and the actual nodes come from the imported subscription. Note that TUN mode adds no new protocol: traffic leaving the adapter still enters the same SOCKS inbound on 10808, and the handshake and encryption are decided entirely by the node — VMess, VLESS, Trojan and SS alike.
Steps to turn on TUN mode
The order below follows the v2rayNG 1.9.x menu layout. A few versions word the menu entries slightly differently, but the steps themselves are unchanged.
- Import a subscription first and confirm the nodes work. Use the menu on the right of a node row to run a real connection latency test; a node showing -1 failed the handshake, so switch to one that connects before you blame TUN for a node problem.
- Open the sidebar → Settings and make sure the connection mode is VPN (TUN) mode. v2rayNG uses VpnService to create the virtual adapter; on some versions this is a VPN mode switch, on others there is no separate switch and tapping connect goes straight through VpnService. Either way the following steps are the same.
- Sidebar → Routing settings → Predefined rules, then pick Bypass LAN and mainland. Local network devices and mainland China sites go direct, and only traffic that needs a proxy reaches the node.
- Settings → Domain resolution strategy, choose IPIfNonMatch. This option decides at which stage of rule matching a domain gets resolved, and it matters later when you check DNS.
- To control things per app, go to Settings → Per-app proxy, turn the switch on and choose Proxy selected apps only or Bypass selected apps, then tick the target apps in the list.
- Go back to the main screen and tap connect. The first time, the system shows a connection request dialog — tap Allow. The VPN key icon then appears in the status bar and v2rayNG's running notification appears in the notification shade, and capture begins.
Per-app proxy and TUN are the same layer
Per-app proxy is not a second tunnel. It uses the same VpnService as TUN: the allow list and the exclude list are filtered by the system at the VPN layer, so traffic from excluded apps never reaches the virtual adapter and therefore never reaches Xray. Turning on per-app proxy after TUN does not create double proxying — it only narrows what gets captured.
Permission and staying alive in the background
Authorization happens at the system level, but staying alive depends on the vendor's background policy. Chinese OEM ROMs often kill the VPN service a few minutes after the screen goes off: the key icon disappears from the status bar, traffic counters stop rising, and reopening the app shows the connection back in the disconnected state.
- Battery: system Settings → Apps → v2rayNG → Battery, choose Unrestricted or turn off battery optimization.
- Autostart: allow v2rayNG to autostart in the autostart manager, and lock the app in the recent tasks list so a one-tap cleanup does not kill it.
- Background pop-ups: the system must not block v2rayNG's connection request dialog; granting this permission reduces failed authorizations.
- Always-on VPN: since Android 7.0, Settings → Network & internet → VPN has an Always-on VPN option that can keep v2rayNG resident and have the system bring it back after a drop.
- Block connections without VPN: the option on the same page cuts off all traffic while the VPN is down. Leave it off while debugging, otherwise it muddles the reason a connection fails.
Conclusion: fix background policy first, then check rules
The same configuration behaving differently on different phones usually comes down to background survival policy rather than the core. Set battery optimization off, autostart and background lock, watch it for a day, and only then look into DNS and routing rules — doing it the other way round wastes a lot of time.
Verify what is being captured
A connected status only means VpnService brought the tunnel up; it does not prove traffic actually reaches the core. Use three reproducible checks to confirm what is captured.
- Compare exit addresses: visit a page that shows your exit IP in a browser and note the result while connected directly; then connect TUN and visit the same page — the IP should change to the node's region and the ISP field should change with it.
- Per-app proxy counter-check: set an app to bypass in Per-app proxy, reopen it and it should show your local IP; untick it, reopen and it should show the node IP. Two different results mean TUN's per-app filtering is working.
- Traffic statistics: turn on Settings → Enable traffic statistics, then after connecting watch whether the up/down counters grow as you browse; if the numbers stay still, traffic is not reaching the core.
Common problems and troubleshooting
Key icon still in the status bar after disconnecting v2rayNG?
The key icon is drawn by the system VPN framework. Tap disconnect once in the v2rayNG main screen and the icon goes away with the VpnService; if it is still there, open system Settings → Network & internet → VPN and check whether another profile is connected, disconnecting them one by one.
TUN is on, but one app still shows a local IP?
Check Settings → Per-app proxy first: with Bypass selected apps, the apps ticked in the list are the ones that skip the proxy; with Proxy selected apps only, the apps left unticked skip it. Check both modes, then reopen the app and test again.
A browser extension still points at 127.0.0.1:10808. Does it need changing?
Better to clear it. If you leave it, requests go into the local inbound through the extension first and bypass TUN's per-app filtering — so if per-app proxy excludes the browser but the extension is still proxying, your tests will give contradictory results.
The system shows a connection request when tapping connect — will it appear again if cancelled?
Yes. The next tap on connect asks for authorization again; cancelling once does not permanently deny it. If the dialog stops appearing altogether, delete the v2rayNG entry in the system VPN list and connect once more — the authorization flow will run again.
Does TUN mode use more battery than the local proxy?
A little. The extra cost is tun2socks' user-space forwarding plus one memory copy, and it shows more when the app stays in the background for hours. If you only use a browser, turn TUN off, or narrow the scope to the apps you need with per-app proxy.
Keep the troubleshooting order fixed: first check whether the background process survived, then whether a routing rule sends the target traffic direct, and last where DNS resolution happens. If all three pass and it still fails, go back to the node and run a real connection latency test.