First, identify the implementation: TUN does not always require a system extension

To enable Clash TUN on macOS, the core needs permission to create a virtual network interface and adjust routes. Clients using mihomo commonly install a privileged helper service, allowing the core to work with the utun interface provided by macOS. Apps built on Apple Network Extension may instead require adding a VPN configuration or approving a network extension. These are separate approaches—you do not need to follow both.

This guide follows the System Settings layout in macOS 13 and later and covers both the helper-service and network-extension approaches. Button names vary by client version; before you begin, note the client version, mihomo version, and macOS version from the About or Core page. Choose an arm64 build for an Apple silicon Mac and an x86_64 build for an Intel Mac. Processor architecture does not remove network permission requirements.

A virtual network interface handles IP traffic; it does not automatically proxy every connection

TUN is a layer 3 virtual network interface. After system routing sends an app's IP packets through the virtual interface, the proxy core reads them and uses its rules to select a proxy node, connect directly, or reject the connection. This can cover many apps that ignore system HTTP proxy settings, but coverage still depends on routing, exclusions, IPv6 settings, and other VPNs.

So “enable TUN” and “proxy everything” are separate settings. With TUN in rule mode, connections matching DIRECT still connect directly. Global mode does not guarantee that traffic excluded by the system will pass through the core, either. UDP availability also depends on the selected node, protocol, and server support.

System proxy vs. TUN: choose based on the apps you use

Feature System proxy TUN mode
Traffic entry point Apps read the system proxy settings and connect to a local proxy port System routing sends matching IP packets to a virtual interface
Common use cases Browsers and desktop apps that follow system proxy settings Some command-line tools, games, and apps that ignore proxy settings
UDP handling A standard HTTP proxy does not generally carry UDP Can receive UDP, but the outbound route must also support UDP forwarding
Permissions Changing system proxy settings may require authorization Usually requires authorization for a helper service or network extension
Impact of failures Mainly affects apps that use the proxy Routing or DNS issues may disrupt networking across the entire Mac

If Safari is all you need for web access, start with the system proxy. If your browser works but command-line tools connect directly, check each tool's proxy options before enabling TUN. TUN covers more traffic, but adds routing and DNS troubleshooting—it is not a latency-boost setting.

Verify the node with the system proxy first

  1. Import your subscription and update it. Make sure the client passes its configuration syntax check.
  2. Select rule mode and choose an available node in the proxy group.
  3. Enable the system proxy, visit the service you need in a browser, and check the connection log.
  4. Once the node is working, turn off the system proxy and test TUN on its own to avoid confusing the two traffic paths.

Some clients let you use the system proxy and TUN at the same time, but for initial troubleshooting, use only one traffic entry point. Switching to TUN will not fix an expired subscription, an incorrect node password, or an unreachable server.

Before you enable TUN: back up your configuration and note your network settings

Move the client into Applications before launching it. Running it from a disk image, or moving it after installing its service, can leave the helper service pointing to the wrong app location. Back up your current configuration, override files, and proxy group selection. Subscription links contain access credentials, so do not paste them into a public support ticket.

  • Pause other tunnels: Temporarily disconnect other VPNs, TUN proxies, and network tools that may take over routing. On a managed device, check with your IT administrator first; do not remove company-managed network configurations.
  • Note your DNS settings: Open System Settings → Network → your current network service → Details → DNS, and record any manually configured server addresses.
  • Check the local port: Find the actual HTTP, SOCKS, or mixed port in your client. The example below uses 7890; this is not a standard port for every client.
  • Keep an offline fallback: Open the client settings in advance and locate the TUN switch and helper-service controls, so you know how to recover before a network outage.

In Terminal (Applications → Utilities → Terminal), run the following read-only commands to record the current state. The output includes network addresses and interface details, so redact it before sharing.

sw_vers
uname -m
scutil --proxy
scutil --dns
route -n get 1.1.1.1
ifconfig -l

uname -m usually returns arm64 in a native Apple silicon Terminal session. If Terminal runs through Rosetta, it may show x86_64, so check your Mac model in the Apple menu → About This Mac. Use route -n get to check routing for a specific destination; this is more useful for verifying TUN than checking only the default route.

Path 1: Install a helper service and enable mihomo TUN

If the settings include “Service Mode,” “Helper Service,” or “Privileged Service,” this is usually the path to follow. The steps below describe the general sequence, not a menu shared by every client. Follow the wording in your current app and its project documentation.

  1. In the client, open Settings and find the service management section. Click Install or Install Helper Service. Confirm the system authentication prompt only after you have initiated this action.
  2. Authorize with an administrator account. macOS may ask for your password or Touch ID. If your account does not have administrator privileges, contact your device administrator.
  3. Wait for the interface to show that the service is running, then restart the core as prompted by the client. The disappearance of the Install button alone does not confirm that the service started successfully.
  4. Open the Network or TUN settings and enable TUN mode. For the first test, keep the protocol stack and routing options recommended by the client.
  5. Check the startup log for permission errors, interface creation failures, or route errors. Then verify that real connections appear in the log.

Privileged helper services usually run through the system service manager; they are not third-party kernel extensions. If no “Allow System Extensions” button appears, that does not mean you missed an authorization step. Do not run the entire graphical client with sudo as a long-term workaround for permission issues.

If the helper service will not start: what to check

  • Make sure you launched the same client copy from Applications, not a copy in Downloads or on a disk image.
  • If the service stops matching the app after an update, use the client's built-in options to uninstall and reinstall the service.
  • In macOS 13 and 14, check background items under System Settings → General → Login Items. In macOS 15, the corresponding section is Login Items & Extensions. An entry appears only if the app has registered a background item.
  • Note the time and error message of the first failure. Do not try to troubleshoot by installing helper services from several clients.

The client determines the service identifier, install path, and management commands. Do not copy another project's launchctl removal commands or bulk-delete files from /Library/LaunchDaemons/.

Path 2: Approve the VPN configuration and network extension

Follow this path only if the client explicitly uses Network Extension and macOS displays the corresponding request. Apple's Network Extension framework supports several deployment models. VPN configuration permission, an app extension, and system extension approval are separate steps—not all prompts are “driver authorization.”

  1. Enable the tunnel feature in the client. If macOS asks to add a VPN configuration, verify the app name and choose Allow.
  2. If macOS says a system extension was blocked, follow the prompt to open System Settings. In macOS 13 and 14, approval is commonly available near the bottom of Privacy & Security, and appears only when an approval request is pending.
  3. In macOS 15, check System Settings → General → Login Items & Extensions → Network Extensions. The list depends on the extension type used by the app and its installation status.
  4. Restart only if macOS or the client asks you to. Then reconnect the tunnel in the app and check its status under VPN or the relevant section of Network in System Settings.

Do not remove VPN configurations unrelated to the client you are troubleshooting. Personal VPNs, company VPNs, and content filters may belong to different network components. Before removing anything, note its name and purpose; whenever possible, disconnect or uninstall it through its own app.

mihomo configuration: check TUN, DNS, and rules separately

Many graphical clients merge subscriptions, overrides, and app settings before startup. Direct edits to cached subscription files may be overwritten at the next update. Prefer the client's TUN settings or persistent override feature, and inspect the final runtime configuration. The original Clash, older Premium versions, and mihomo do not all support the same configuration options.

The following is a partial mihomo configuration example, not a complete subscription you can import as-is. It has no nodes, proxy groups, or rules. Merge it into your existing configuration and avoid duplicate top-level tun or dns keys. If the client generates these fields, use its configuration mechanism instead.

tun:
  enable: true
  stack: system
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53
    - tcp://any:53

dns:
  enable: true
  listen: 127.0.0.1:1053
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  nameserver:
    - 223.5.5.5
    - 1.1.1.1
  • auto-route: Lets the core automatically configure routes to TUN. Check the logs and actual routing to confirm it worked.
  • auto-detect-interface: Attempts to identify the outbound interface. If Wi-Fi, Ethernet, and another VPN are active at the same time, check carefully that the correct route is selected.
  • dns-hijack: Sends eligible traditional DNS requests entering TUN to the core's DNS handler. This example covers UDP and TCP on port 53; it does not automatically decrypt arbitrary encrypted DNS.
  • fake-ip-range: Allocates address space for fake-IP mappings; it is not a proxy server address. Adjust it if it conflicts with your existing network.

The DNS upstream in this example is a plaintext resolver, included only to illustrate the configuration structure—not as a recommendation for every network. Corporate intranet domains may resolve only through company DNS. Plan settings such as nameserver-policy by domain; do not simply replace every DNS path with a public resolver.

Two easy-to-miss limitations

Test IPv6 separately. This example is not a complete IPv6 routing setup. If your network supports both IPv4 and IPv6, check the core's IPv6 settings, TUN routes, and actual connection logs. Passing an IPv4 test alone does not prove that all connections are routed as expected.

Working DNS does not mean your rules are correct. Rules are still evaluated in order, and the policy is usually decided by the first match. Specify in your rules whether corporate domains should connect directly or use a particular outbound route. TUN does not fix rule order or fill in rule sets missing from your subscription.

Verify TUN is working: check interfaces, routes, and connection logs

An enabled TUN switch only confirms that the interface state changed. Seeing utun is not enough to confirm that the current client has taken over traffic. macOS services and other VPNs can also create utun interfaces, and their numbers can change. Do not assume utun0 or utun3 is always the right one.

ifconfig -l
route -n get 1.1.1.1
scutil --dns
scutil --proxy
lsof -nP -iTCP:7890 -sTCP:LISTEN

Compare the interface lists before and after enabling TUN, then check whether routes to specific destinations match the client's design. Some implementations add multiple, more-specific routes rather than replacing the single default route. The lsof command below only checks whether a process is listening on the example local port; it does not prove that TUN is working.

Make a request without an explicit proxy

curl --noproxy '*' --connect-timeout 10 --max-time 20 -I https://example.com

This command does not explicitly use an HTTP or SOCKS proxy, making it useful for testing TUN. It uses a 10-second connection timeout and a 20-second total timeout so it returns promptly on failure. Then find example.com on the client's Connections page and check the matched rule, proxy group, and actual node. An HTTP response only shows that the request completed; it does not prove that it went through a proxy.

  • First test a destination that should connect directly and confirm the log shows the expected direct policy.
  • Then test a destination that should use a proxy and confirm it matches the correct proxy group, not an unintended fallback at the end of the rules.
  • If you need UDP, test with the UDP app you actually use. A successful TCP request does not prove that UDP forwarding works.
  • Test again after switching Wi-Fi networks or waking your Mac from sleep. Check whether automatic interface detection follows the network change.

Common problems and recovery steps

All network access stops after enabling TUN

Turn off TUN first and confirm that your basic network access returns. Then look for the earliest error in the log. If disabling TUN restores access, check DNS requests, routing settings, and the outbound interface. If access is still unavailable, check whether the system proxy points to a local port whose app has exited and whether another VPN is still connected.

System proxy works, but TUN reports insufficient permissions

Check the helper service before changing nodes. Confirm that the service is installed, the app's current path has not changed, and the service was updated after the app upgrade if needed. If the error specifically mentions creating an interface or adding a route, save that log entry and use the client's service management tools to fix it.

Web pages load, but games or voice chat fail

Check whether the connection actually enters TUN, whether the node supports UDP, and whether the rules select the correct outbound route. If only certain networks fail, then investigate path MTU or carrier restrictions. Do not copy a smaller MTU value without testing; first document the failure scenario and change one thing at a time.

Domains stop resolving after waking from sleep

Reconnect TUN first, then check the active outbound interface and DNS status. To clear the system DNS cache, run the commands below only after confirming that routing and the core's DNS are working again. These commands will not fix an incorrect DNS upstream or rule.

sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

How to revert when you are done

  1. Turn off TUN in the client and wait for the connection to disconnect before quitting the app. Do not force-quit the core first.
  2. If you enabled the system proxy, turn it off in the client too, then use scutil --proxy to check for leftover settings.
  3. Restore any manually configured DNS servers you noted earlier. If the network originally used automatic DNS, do not leave temporary public DNS servers in place.
  4. If you no longer use the client, uninstall its helper service using the option provided by the app. For a Network Extension setup, remove the relevant configuration according to the app's uninstall instructions.
  5. Test your direct connection again. If needed, disconnect and reconnect the current network service.

For further troubleshooting, see the troubleshooting guide. For help importing a subscription and choosing a proxy group, see the quick start guide. When reporting an issue, include your macOS version, client and core versions, which setup path you used, and the first error message with sensitive details removed. This is more useful than a screenshot of the toggle alone.