First, distinguish traffic entry from routing mode

System proxy and TUN mode determine how traffic enters the client; rule, global, and direct modes determine how the client routes it afterward. These settings operate at different layers. Enabling TUN does not send every connection through a remote proxy, and choosing global mode does not automatically route every app through the client.

A connection can be understood in the following order. Proxy group selection and node availability in a subscription come into play only after traffic reaches the client. If a connection never enters the core, switching nodes repeatedly is unlikely to change the outcome.

App initiates a connection
  → System proxy port or TUN virtual interface
  → Clash / mihomo core
  → Outbound mode and rule evaluation
  → DIRECT, proxy node, or REJECT

System proxy: Apps connect to a local port

A system proxy is essentially a set of network settings that apps can read. For example, a client might listen on the local mixed port 127.0.0.1:7890 and set that address as the system proxy. Apps that honor the setting connect to the local port first, and the core then connects to the destination. 7890 is only an example; use the port shown in the client settings.

How HTTP, HTTPS, and SOCKS differ

  • HTTP proxy: The app sends HTTP requests to the proxy server for handling.
  • HTTPS through an HTTP proxy: The app typically sends a CONNECT request to establish a tunnel, then completes the TLS handshake inside it. This does not mean the client decrypts HTTPS traffic.
  • SOCKS5: The app negotiates the destination address through SOCKS. Whether it sends the domain name to the proxy for resolution depends on the app and connection method.
  • Mixed port: A single listening port accepts both HTTP and SOCKS proxy connections. It does not force every program on the system to use that port.

Where to check on macOS

On macOS 13 and later, go to System Settings → Network → your current network service (such as Wi-Fi) → Details → Proxies. Check the server and port for Web Proxy, Secure Web Proxy, and SOCKS Proxy. Labels may vary slightly by macOS version. After switching between Wi-Fi, Ethernet, or another network service, check the active service—not just the one you used previously.

Browsers, terminals, and desktop apps do not necessarily use the same proxy settings. Some apps read the system settings; others have their own proxy options. Command-line tools may also use the HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, and NO_PROXY environment variables. So if a browser works but a terminal does not, check for differences in how traffic enters the client before assuming the node is at fault.

TUN mode: Route IP traffic through a virtual interface

TUN provides a virtual Layer 3 network interface. Apps create connections as usual, while the operating system routes matching IP packets through the virtual interface for the core to handle. Because apps do not need to support HTTP or SOCKS proxies, TUN is often useful for programs that ignore system proxy settings.

On macOS, virtual interfaces typically appear as devices in the utun family. System VPNs and other network services can create similar interfaces, though, so seeing a utun device alone does not confirm that the client has captured traffic. Check the client logs, routes, and connection records as well.

Requirements and limitations

  • Permissions: Creating an interface and configuring routes usually requires administrator approval or a client helper service. Approval does not guarantee that routes are configured correctly.
  • Core: TUN availability and support for specific network stacks and fields depend on the core in use. A client branded as Clash does not necessarily run mihomo.
  • UDP: TUN can route eligible UDP traffic into the core, but the remote node and protocol must also support UDP forwarding. Enabling the toggle cannot add capabilities the node does not have.
  • Coverage: IPv6, local network traffic, excluded routes, and other VPNs can all affect what gets captured. TUN does not capture every kind of Layer 2 broadcast traffic.

In mihomo, auto-route configures relevant routes automatically, while auto-detect-interface detects the outbound interface. These options help with common network setups, but cannot guarantee compatibility with corporate VPNs, virtual machine networks, or multi-interface routing policies.

System proxy vs. TUN in practice

CheckSystem proxyTUN mode
How traffic entersApp connects directly to a local proxy portRoutes send IP packets through a virtual interface
App compatibilityApp must read system settings or be configured to use a proxyUsually works without a proxy option in the app
UDP requirementsDepends on the app and proxy protocol; a standard HTTP proxy does not cover all UDP trafficDepends on routes, the core, and UDP support on the node
Permissions and scopePrimarily changes proxy settings for the network serviceInvolves a virtual interface, routes, and potentially DNS capture
Where to start troubleshootingListening port, app proxy settings, bypass listPermissions, routes, DNS, IPv6, and VPN conflicts

Neither option is inherently faster. When the same request ultimately uses the same node, performance usually depends more on node load, connection quality, and the destination service. TUN adds a traffic-processing layer, but that does not mean it is necessarily slower. The system proxy path is more direct, but that does not guarantee an app will use it as expected.

DNS: Where resolution happens determines what domain information is available

With a system proxy, an app may send the domain name to the proxy, or resolve it locally first. For example, curl typically resolves the destination locally with socks5://, while socks5h:// sends the destination domain to the SOCKS proxy. The resolution path can differ even when the port is the same.

TUN primarily receives IP packets. If an app has already resolved a domain to an IP address, the core may not know the original domain automatically. DNS interception, Fake-IP mapping, and traffic sniffing can provide domain information for domain-based rules, but each works differently.

  • DNS interception: Routes matching DNS requests to the core's DNS module. Intercepting common DNS traffic on port 53 does not decrypt an app's built-in DoH or DoT.
  • Fake-IP: The core returns a mapped address and keeps the association between the domain and address. A commonly used range is 198.18.0.0/16; these addresses are not remote node addresses.
  • Sniffing: Attempts to recover the destination domain from visible protocol data, such as SNI in some TLS ClientHello messages. It does not decrypt HTTPS, and it has limitations with encrypted ClientHello and other cases.

How to check a mihomo configuration snippet

The snippet below shows only relevant fields, not a complete configuration. Before using it, confirm that the client is actually running a mihomo version that supports these fields, and keep the existing DNS upstreams, proxy nodes, and rules. If the client generates its configuration through a graphical settings panel, use that panel where possible to avoid manual changes being overwritten when the subscription refreshes.

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53

dns:
  enable: true
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16

Troubleshoot one entry path at a time; don’t change multiple toggles at once

Step 1: Test the local proxy port on its own

Turn off TUN first, but leave the core running. Then test with a command that explicitly specifies the proxy. The example assumes a mixed port of 7890; update it if the client shows a different port. The command sets a 15-second timeout and prints connection details to help distinguish a refused connection, a TLS error, and a timeout at the destination.

curl -I -v --max-time 15 \
  --proxy http://127.0.0.1:7890 \
  https://example.com/

curl -I -v --max-time 15 \
  --proxy socks5h://127.0.0.1:7890 \
  https://example.com/

If the connection to 127.0.0.1:7890 is refused, first check that the core is running, the port matches, and no other program is using it. If the proxy handshake succeeds but the destination times out, check the node and outbound rules. A successful test to one address confirms only that this particular request path works—not that every site is reachable.

Step 2: Check whether apps use the system proxy

Turn on the system proxy, then run scutil --proxy in Terminal on macOS to inspect the current proxy settings. Also check the app's own proxy settings and bypass list. In Terminal, use env | grep -i proxy to check for existing proxy variables. A correctly configured system proxy and an app actually using it are two separate things to verify.

Step 3: Test TUN on its own

Turn off the system proxy, enable TUN, and reconnect the target app. Use the command below to prevent curl's explicit proxy settings from affecting the test, then check the client's connection log. This command disables curl's proxy use; it does not bypass TUN routing.

curl -I -v --max-time 15 --noproxy '*' https://example.com/

If there is no matching connection record, focus on the TUN startup log, excluded routes, IPv6 routing, and other VPNs. If a record appears, check the matched rule and final outbound. Long-lived connections established before changing settings may keep using the old path; if needed, quit and reopen the target app.

Choosing a setup: Start with the system proxy, add TUN when needed

  • Mostly browsing: The system proxy usually makes it easier to see which traffic is affected. First confirm that the browser follows the system settings.
  • Developer tools in Terminal: Start by setting proxy options or environment variables explicitly. Consider TUN if you need to handle several apps that do not support proxies.
  • Games and other UDP apps: First confirm that the node supports UDP, then check TUN routes and the app's connection records. Enabling an HTTP system proxy alone usually will not cover this traffic.
  • Corporate VPNs and intranet access: Check intranet domains, private IP ranges, and DNS separately. Adjust excluded routes and direct rules if needed; do not overwrite network settings required by your organization.

You can enable the system proxy and TUN at the same time, but troubleshoot them separately first. An app explicitly connecting to a local proxy port may still use that proxy entry point, while TUN captures other traffic. Do not assume the two toggles mean every connection passes through two remote proxies, or that the core automatically resolves every routing conflict in every configuration.

How to restore connectivity after turning them off

  1. Turn off TUN and the system proxy in the client, then quit the client normally so it can remove the routes and proxy settings it created.
  2. Check the proxy settings for the current network service and remove any entries pointing to a local port that is no longer listening. Contact your administrator about organization-managed settings.
  3. Check whether proxy environment variables, app-specific proxy settings, or another VPN are still active, then reconnect to the network.
  4. If local network access or DNS resolution is still failing, record the route and DNS state, then follow the recovery steps for your specific client. Do not blindly delete all network services.

The definitive test is the connection path you can verify: whether traffic enters the core, how the domain is resolved, and which outbound the rule selects. Checking these three separately usually pinpoints the issue faster than repeatedly toggling the system proxy and TUN.