1. What TUN Mode Changes for Developer Tools
Git, package managers, container tools, and build scripts do not always use the operating system’s HTTP proxy setting. A browser may work through Clash while git, npm, pip, or docker still times out. TUN mode addresses this gap by creating a virtual network interface and routing eligible device traffic through the Clash core. Instead of relying only on an application to understand a proxy setting, the core can receive connections at the network layer and apply its normal routing rules.
TUN is a traffic-capture mechanism, not a guarantee that every request will use a proxy. The core still needs a working configuration, DNS must resolve destinations correctly, and rules must select an available outbound policy. Local network exclusions, applications with their own networking stacks, and traffic that never reaches the virtual interface can all affect the result. The practical test is whether the request appears in the client’s connection list and which rule and policy it matched.
This guide focuses on Clash clients running a compatible Meta/mihomo core, including clients such as Clash Verge Rev. Labels and permission prompts vary by client and operating system, so verify the core version shown in the application rather than relying on the client name alone. Older cores may not support the same TUN fields or behavior.
| Method | What it covers | Best use |
|---|---|---|
| System proxy | Applications that honor the operating system’s HTTP or SOCKS proxy settings | Browsers and tools with native proxy support |
| Proxy environment variables | Commands and processes that honor variables such as HTTPS_PROXY | A small number of CLI tools without TUN |
| TUN mode | Eligible device traffic routed through a virtual interface | Tools that ignore the system proxy or use varied network libraries |
These methods can coexist, but enabling all of them without a plan makes diagnosis harder. For a first test, use one traffic path at a time: either enable TUN and leave tool-specific proxy variables unset, or keep TUN off and configure the tool to use Clash’s mixed port. A common mixed port is 7890, but check the active configuration or client settings before using it; ports are configurable and may differ.
2. Enable TUN Safely on Windows and macOS
Before switching modes, save the active configuration or note how to restore the previous client settings. Confirm that the selected profile has a usable proxy group and that Rule mode is active. Global mode can be useful for a short connectivity test, but it does not test the service-specific rule behavior described below. If the client offers a core information screen or startup log, check that the running core is mihomo or another compatible implementation.
Windows: permissions and the virtual adapter
- Open the client’s settings and locate its TUN, service mode, or network stack section. The exact menu name depends on the client version.
- Enable TUN and approve the requested administrator or service permission. Some clients install or start a helper service; approve only the expected prompt from the client you installed.
- Allow the client to create its virtual adapter, then wait for the core to report that TUN has started. If Windows displays a network permission prompt, check that the application name matches the client.
- Test one command, such as
git ls-remoteagainst a repository you can access. Check the Clash connection list at the same time and verify the matched rule and outbound.
If the TUN switch immediately turns off, inspect the client log for permission, adapter, or core-startup errors. Close other VPN clients temporarily when practical: another virtual adapter or route manager can compete for routes. Do not delete network adapters or reset the entire Windows network stack as a first response. Record the error and try a normal client restart before making system-wide changes.
macOS: approve the network extension
- Enable TUN in the client and follow the macOS prompt to allow the requested network extension or VPN configuration.
- If macOS directs you to System Settings, review the prompt there. Depending on the macOS release and client, the permission may appear under Network, Privacy & Security, or a VPN and filters section.
- Return to the client and check that the core reports a running TUN interface. If the status remains pending, quit and reopen the client after approving the permission.
- Run a single CLI request and inspect the connection list. Keep the test narrow until DNS, routing, and the selected policy are confirmed.
macOS may ask for authorization again after a client update, a core change, or a permission reset. A visible VPN status does not by itself prove that the intended Clash profile is handling a particular connection. Confirm the destination, rule, and outbound in the client. On either platform, turn TUN off to return to the previous routing behavior; do not leave an abandoned virtual route active while troubleshooting a separate network problem.
3. Route Git, npm, PyPI, and Docker by Domain
TUN gets eligible connections to the core; the rules section decides what happens next. Put service-specific rules above broad rules such as GEOIP or MATCH, because the first matching rule normally determines the route. The policy name in each rule must exactly match a proxy group or node already defined in the active configuration. In this example, Developer Proxy is a placeholder name, not a built-in Clash policy.
The domains below cover common endpoints, not every endpoint used by every workflow. A Git operation may fetch objects from a content host; a package manager may follow redirects to a file host; Docker may contact an authentication service before pulling an image. Use the connection list to discover the actual destination for your command, then add a narrowly scoped rule if needed.
mode: rule
rules:
# Git hosting and common GitHub content endpoints
- DOMAIN-SUFFIX,github.com,Developer Proxy
- DOMAIN-SUFFIX,githubusercontent.com,Developer Proxy
- DOMAIN-SUFFIX,githubassets.com,Developer Proxy
- DOMAIN-SUFFIX,gitlab.com,Developer Proxy
# JavaScript packages
- DOMAIN-SUFFIX,npmjs.org,Developer Proxy
- DOMAIN-SUFFIX,npmjs.com,Developer Proxy
# Python package index and downloadable files
- DOMAIN-SUFFIX,pypi.org,Developer Proxy
- DOMAIN-SUFFIX,pythonhosted.org,Developer Proxy
# Docker Hub registry and authentication
- DOMAIN,registry-1.docker.io,Developer Proxy
- DOMAIN,auth.docker.io,Developer Proxy
- DOMAIN-SUFFIX,ghcr.io,Developer Proxy
# Keep the existing local, regional, and fallback rules below these entries
- MATCH,Existing Policy
Merge this example into the active configuration rather than pasting a second top-level rules key. Replace Developer Proxy and Existing Policy with policy names that already exist in your profile, or add appropriate groups using the format supported by the running core. If your configuration already has more specific rules for these hosts, avoid adding duplicates without checking their order. A broad rule earlier in the list may capture the connection before the entries shown here.
Git over HTTPS usually uses port 443, while Git over SSH commonly uses port 22. Domain rules can route a known SSH hostname, but an SSH connection made directly to an IP address may not provide a domain for matching. If you intentionally use SSH and need all SSH destinations to use the developer policy, a port rule can be added above broad fallbacks:
- DST-PORT,22,Developer Proxy
This sends all matching TCP traffic on destination port 22 to that policy, not just Git. Apply it only if that broader behavior is acceptable. Also check that the remote URL is actually an SSH URL such as git@host:owner/repository.git; changing TUN will not fix an incorrect hostname, key, or repository permission.
| Workflow | Common domains | Check when a request still fails |
|---|---|---|
| GitHub | github.com, githubusercontent.com, githubassets.com | Whether the failing operation uses HTTPS or SSH and whether a redirected content host appears |
| npm | npmjs.org, npmjs.com | The configured registry, lockfile source, and any package-specific download host |
| PyPI | pypi.org, pythonhosted.org | Whether the index is a mirror and whether the package file host differs |
| Docker Hub | registry-1.docker.io, auth.docker.io | Whether the image is hosted on Docker Hub, GHCR, or a private registry |
4. Configure CLI Proxies Without Conflicting with TUN
If TUN is unavailable, a tool-specific proxy is a useful alternative. With TUN enabled, many developers can leave these variables unset and let the virtual interface capture eligible traffic. If you deliberately use both mechanisms, understand the path: the command may connect to Clash’s local proxy port, and the core then opens the remote connection. A stale proxy variable pointing to a port that is no longer listening can cause failures even while TUN is working correctly.
For a temporary HTTPS proxy test in macOS or a POSIX shell, use the actual mixed port configured in Clash:
export HTTPS_PROXY=http://127.0.0.1:7890
export HTTP_PROXY=http://127.0.0.1:7890
export ALL_PROXY=socks5h://127.0.0.1:7890
curl -I https://pypi.org
unset HTTPS_PROXY HTTP_PROXY ALL_PROXY
socks5h asks the SOCKS proxy to resolve the destination hostname, which can avoid a local DNS lookup in tools that support it. Not every program honors every variable, and some read proxy settings only when they start. For a clean TUN-only test, remove the temporary variables from the shell and launch a fresh command. Shell configuration files such as ~/.zshrc can make a variable persistent, so inspect them if a new terminal keeps using an old proxy.
In PowerShell, the variables can be set for the current session and then removed:
$env:HTTPS_PROXY = "http://127.0.0.1:7890"
$env:HTTP_PROXY = "http://127.0.0.1:7890"
curl.exe -I https://pypi.org
Remove-Item Env:HTTPS_PROXY, Env:HTTP_PROXY -ErrorAction SilentlyContinue
For Git, inspect existing configuration before adding a proxy: git config --show-origin --get-regexp 'http\..*proxy'. A proxy stored in global Git configuration can continue to apply after a shell variable is removed. To remove one only after confirming it is the cause, use git config --global --unset http.proxy if that is the exact key present. Do not set an HTTPS proxy URL for SSH remotes; Git’s HTTP proxy setting does not configure SSH transport.
Package managers can also have independent settings. Check npm’s registry and proxy configuration with npm config get registry and npm config get proxy; for pip, inspect its configuration files and any PIP_INDEX_URL or proxy variables. Docker has daemon-level networking behavior that may differ from the terminal client. If docker pull fails while curl works, test the daemon and its registry access separately rather than assuming the shell’s proxy variables apply to it.
5. Troubleshoot Terminal Traffic Step by Step
Change one variable at a time. A useful reproduction records the operating system, client and core versions, active profile, whether TUN is on, the exact command, and the time of the request. Avoid sharing subscription URLs, access tokens, private registry credentials, or complete environment dumps. A short, redacted log excerpt and the matched connection entry are usually more useful than a screenshot of a terminal timeout alone.
- Confirm capture: Run one request and look for its destination in Clash’s connection list. If no connection appears, check that TUN is running, the process is using the expected network path, and no stale explicit proxy is sending it to the wrong local port.
- Confirm matching: Inspect the matched rule. If a broad rule appears first, move the service-specific entry above it. If the destination is an IP address and a domain rule does not match, investigate DNS behavior or use a suitable IP/port rule deliberately.
- Confirm the outbound: Verify that the selected proxy group contains a usable node and that the group name in the rule is correct. A successful match to a group does not prove that the chosen node can connect.
- Separate DNS from transport: If the connection never reaches the expected domain, check DNS settings and the actual hostname shown by the tool. If it reaches the core but times out while connecting, compare the selected outbound and node logs.
- Test another path: Try one request with TUN disabled and a known-good explicit proxy, or with TUN enabled and proxy variables removed. This helps distinguish capture problems from an application-specific setting.
For example, a successful browser test does not prove that a Docker daemon is routed the same way. The browser may use the system proxy, while the daemon runs as a separate service with different DNS and proxy settings. Likewise, npm install can fail after the registry responds if a package tarball is fetched from a separate host. Match the failed connection in the log before adding more domains or changing global DNS.
When logs show a DNS error, check whether the query is handled by the intended Clash DNS path and whether the client’s TUN DNS interception is active. When logs show a TCP timeout, identify which address timed out: the destination, the proxy server, or another hop. “Timeout” alone does not identify the failing layer. Restore the usual log level after reproducing the issue, and avoid leaving verbose logging enabled for routine use.
FAQ
Does TUN automatically proxy every terminal command?
No. TUN routes eligible device traffic into the core, but rules still decide whether a connection is direct or proxied. Local traffic, unsupported paths, excluded destinations, and service-level network behavior can affect capture. Confirm the request appears in the connection list and inspect its matched rule.
Should I set HTTPS_PROXY when TUN is enabled?
Usually not for an initial TUN test. Start with proxy variables unset so the traffic path is easy to understand. Use explicit variables when a particular tool needs them or when testing the local mixed port; make sure the port matches the active client configuration.
Why does Git work but npm or Docker still fail?
They may contact different domains, use different transports, or run in different processes. npm can download package files from a host other than its registry, while Docker commands may depend on a separate daemon. Find the failed destination in the connection list and add or configure only the route that the evidence requires.
Can I use TUN with any Clash core?
No. TUN configuration and operating-system integration depend on the core and client build. Check the actual running core and version, then confirm that the client supports TUN on your operating system. A profile that parses in one core may not support the same fields in another.