Developer's Guide to Clash TUN Mode for Git, npm, and Docker
What TUN mode changes for terminal traffic
TUN mode gives the Clash core a virtual network interface so it can receive IP traffic that ordinary system proxy settings may not catch. This is useful for command-line tools: Git, npm, pip, and many other programs do not always read the desktop’s HTTP proxy setting. With a working TUN setup, their connections can enter Clash at the network layer and be handled by its rules and proxy groups without configuring a separate proxy for every command.
TUN is not a proxy node or a policy by itself. The client provides controls for enabling the feature and starting the core; the core—often mihomo in newer clients—creates or uses the virtual interface, processes traffic, and applies the active configuration. A connection can still fail if the core is stopped, the selected policy is unavailable, a rule sends it to the wrong place, or DNS cannot resolve the destination.
System proxy mode and TUN mode solve different parts of the problem. A system proxy usually tells compatible applications to connect to a local HTTP or SOCKS proxy, often on a port such as 7890. TUN mode routes traffic through an interface instead. It can help with programs that ignore system proxy settings, but it can also affect applications beyond the terminal. The exact behavior depends on the operating system, client, core version, and TUN stack.
| Mode | How traffic reaches Clash | Typical use | What to verify |
|---|---|---|---|
| System proxy | Compatible applications read the operating system’s proxy setting | Browsers and tools that support HTTP or SOCKS proxies | Proxy address, port, and whether the application honors the setting |
| TUN | IP traffic is routed through a virtual network interface | Applications that do not use the system proxy | Core support, permissions, routes, DNS, and matching rules |
| Per-command proxy | The command or process receives proxy options or environment variables | A single tool, shell, or controlled test | Proxy protocol, environment scope, and application-specific settings |
TUN does not mean “send every connection through a remote proxy.” Clash still evaluates the connection against the active rules. A destination may go to a proxy group, use DIRECT, or match another action. Start by checking that the client is using the intended profile and that the core has loaded it successfully.
Prepare the client, core, and operating system
Before changing YAML or developer-tool settings, note the client name, core name and version, operating system, active profile, and current proxy mode. Menu names differ among Clash Verge, Clash Verge Rev, Mihomo-based clients, and older applications. Look for a TUN or service-mode control in the client, then check its core information and logs rather than assuming the same button or configuration fields exist everywhere.
- Confirm core support. TUN options vary by core and version. A configuration accepted by a recent mihomo build may be rejected by an older or different core. Read the first configuration error in the logs and compare the field with documentation for the installed core.
- Check permissions. Creating a virtual adapter or changing routes may require administrator approval, a privileged helper, or a system service. Approve only the expected client operation. If the client reports that the adapter could not be created, restarting Git or npm will not fix that system-level failure.
- Close competing network tools for a test. Another VPN, firewall, virtual network manager, or proxy client may install routes or filters that conflict with TUN. Record its state first; do not remove a work-managed VPN or security tool without permission.
- Keep a recovery path. Know how to turn TUN off in the client and restore the network by exiting the service normally. Avoid editing routes or DNS blindly. On a managed device, follow the organization’s network policy.
A minimal mihomo-style example can help explain the fields, but it is not a drop-in configuration for every client. Use the configuration editor or override mechanism supported by your client, preserve the existing profile, and validate the result before applying it. Some clients expose TUN options in their interface or merge them into the generated configuration.
tun:
enable: true
stack: mixed
auto-route: true
strict-route: true
auto-detect-interface: true
dns-hijack:
- any:53
These settings have platform and version implications. For example, the available TUN stack and route behavior can differ, and DNS hijacking should be considered alongside the core’s DNS configuration. If the core rejects a field, remove nothing at random: identify the unsupported option and consult the matching core documentation. A client may also generate part of this section automatically, so avoid maintaining a duplicate definition that conflicts with its controls.
Enable TUN and verify the traffic path
Open the client’s TUN settings, enable the feature, and grant the requested permission if the client and system are trusted. Wait for the core to report that it started; a checked toggle alone does not prove that an interface or route is active. If startup fails, open the core log and look for permission errors, adapter creation failures, invalid fields, or route conflicts before retrying.
Use a simple sequence to separate routing from application problems. Run a DNS lookup, then an HTTPS request, and inspect the client’s Connections or equivalent page while the request is active. Menu locations and labels vary, but connection details commonly show the destination, matched rule, and selected policy. A request appearing there is evidence that traffic reached the core; it does not by itself prove that the remote connection succeeded.
nslookup registry.npmjs.org
curl -I --connect-timeout 10 https://registry.npmjs.org/
git ls-remote https://example.com/OWNER/REPOSITORY.git
The repository address above is a placeholder: replace it with a repository you are authorized to access. On systems without curl or nslookup, use an equivalent HTTPS client and DNS lookup tool. Run each test once, note its time, and correlate it with the client’s connection list and core logs.
- No connection appears in Clash: The command may bypass the host’s TUN path, the virtual interface may not be active, or the request may not have started. Verify TUN status and operating-system routes before changing proxy rules.
- A connection appears but uses the wrong policy: Check the matched rule, destination domain or IP, and the policy group’s current selection. Rules are evaluated in order; an earlier broad rule can take precedence over a later, more specific rule.
- The policy is correct but the request times out: Test the selected node and remote service separately. A TUN interface cannot repair an unreachable node, expired credentials, or a service that is unavailable.
- DNS lookup fails while an IP request works: Investigate the active DNS configuration and any DNS interception settings. Do not immediately add public resolvers: DNS choice can affect privacy, split-horizon domains, and access to local services.
When a request should use a proxy, confirm that the relevant domain or destination is routed to a proxy group and that the group has a usable selection. If a private registry, internal Git server, or local development service must stay direct, create a narrow rule for that destination rather than changing the final fallback rule for all traffic.
Use Git, npm, and pip without per-command proxy flags
Once TUN captures traffic and the rules are correct, many tools can connect without custom proxy options. Test one tool at a time and distinguish HTTPS from SSH: the two Git transports use different connection paths and can match different rules.
Git over HTTPS and SSH
For an HTTPS remote, run git ls-remote or a small fetch and check the connection entry in Clash. If a previous setup stored a proxy in Git configuration, Git may use that explicit proxy instead of relying only on TUN. Inspect the relevant settings with git config --show-origin --get-regexp 'http\..*proxy|http.proxy'. Do not remove a proxy required by a particular repository; first identify whether it is a global, system, or repository-level setting.
SSH remotes such as [email protected]:team/project.git do not use an HTTP proxy setting. TUN may capture the resulting TCP connection, but the rule must route the destination and port appropriately. SSH commonly uses port 22, though servers can use another port. If HTTPS works and SSH does not, compare the transport, destination, and port before concluding that TUN is broken. Some hosting providers also offer an HTTPS-based Git transport for environments that block SSH.
npm and pip registries
Try a read-only metadata request before installing packages. For npm, npm view lodash version checks registry access without changing a project’s dependency tree. For pip, python -m pip index versions requests can test index access where supported by the installed pip version. A command may contact more than one host, such as a package registry and a separate file host for downloads, so check the actual failed hostname in the output and Clash connection list.
Inspect existing tool-level proxy settings before removing or adding any. npm can have proxy values in its configuration, while pip may read environment variables or configuration files. Shell variables such as HTTP_PROXY, HTTPS_PROXY, and ALL_PROXY can also affect some programs. These settings are not required merely because TUN is enabled, and keeping stale values may send a tool to an unavailable local port. Check the current values with the tool’s own configuration command or the shell’s environment inspection, then remove only a setting you have confirmed is unwanted.
Do not place subscription URLs, proxy passwords, or access tokens in shared terminal screenshots. Package managers and Git can include URLs or credentials in logs, shell history, and configuration files. Redact secrets before sharing a failure report.
Account for Docker and virtualized networking
Docker is the most common exception to the assumption that host TUN automatically captures every command. A Git or package-manager process running directly on the host uses the host’s network path. A process inside a Linux container, Docker Desktop VM, or remote Docker daemon may use a separate network namespace or virtual machine. Its traffic does not necessarily traverse the same host routes as an ordinary terminal process.
First identify where the container actually runs. With Docker Desktop, containers commonly run inside a managed virtual machine; with a Linux Docker Engine, bridge networking uses forwarding and NAT rules. Remote contexts send work to a daemon on another machine. In each case, test the host and container separately, and inspect the active Docker context with docker context show. A successful host-side curl is not proof that the container has the same DNS or egress path.
- Run a short DNS and HTTPS test in the container using an image and tools already approved for your environment. If the image lacks diagnostic tools, use an existing development image rather than downloading an unknown image solely for troubleshooting.
- Check whether the container resolves the expected registry hostname. Compare its resolver configuration with the host, but do not copy a host resolver address blindly: an address reachable from the host may not be reachable from the container or VM.
- Inspect the failed destination and route in the appropriate layer. For Docker Desktop, check the client and VM-related logs or settings available in that version. For Linux Engine, consider bridge forwarding, firewall rules, and the host’s forwarding path.
- Use Docker’s supported proxy configuration only when the daemon, build process, or container needs an explicit proxy. Daemon proxy settings, build-time proxy arguments, and environment variables inside a running container affect different stages; none should be assumed to configure all the others.
Builds may also behave differently from interactive containers. A build step can run in an isolated network environment, use cached layers, or contact a registry before the container starts. Record whether the failure occurs during image pull, build, or application runtime. This narrows the problem to the Docker client, daemon, build network, or container process instead of prompting broad changes to TUN routes.
Troubleshoot by symptom, not by switching settings at random
| Symptom | Likely layer | Focused check |
|---|---|---|
| TUN cannot start | Client, core, permissions, or adapter | Read the first core error; verify core support and the requested system permission |
| Browser works, terminal command fails | Application settings, rule, or transport | Check whether the command has a stale explicit proxy and inspect its connection in Clash |
| Domain lookup fails across tools | DNS configuration or DNS routing | Compare lookup results, core DNS logs, and whether the failure is limited to a private domain |
| Host works, container fails | Docker namespace, VM, daemon, or container DNS | Test from inside the failing environment and identify whether Docker is local or remote |
| Connection reaches Clash but times out | Policy, node, remote service, or firewall | Check the matched policy and test the node or destination independently |
For each test, keep a short record: time, exact command with credentials removed, hostname, whether the connection appeared in Clash, matched rule, selected policy, and the first relevant log error. This is more useful than a screenshot of a failed terminal alone. If the issue started after a profile update, compare the active rules and DNS settings with a known-good backup before editing multiple sections.
When finished, test both proxied and direct destinations that matter to your workflow, including local development services if applicable. Confirm that TUN remains active after restarting the client, and that the client has not left an unintended system proxy or route behind when disabled. Keep a working profile backup so an experimental DNS or routing change can be rolled back.
FAQ
Does TUN replace the system proxy?
No. TUN routes IP traffic through a virtual interface, while the system proxy advertises a local proxy endpoint to applications that support it. Some users run both, but that can make the path harder to understand. For diagnosis, note which mode is enabled and check whether the target application has its own proxy setting.
Do Git, npm, and pip need port 7890 when TUN is enabled?
Not just because TUN is enabled. Port 7890 is a common example for a local proxy listener, not a universal TUN port. A tool-level proxy is only needed if you intentionally want that tool to use the local HTTP or SOCKS listener, or if the traffic path requires an explicit proxy.
Why does Docker still fail when host terminal traffic works?
The container may use a separate network namespace, Docker Desktop VM, remote daemon, or different DNS resolver. Test from inside the failing environment and determine whether the error occurs during image pull, build, or runtime. Host connectivity alone does not establish the container’s route.
What should I check if internet access stops after disabling TUN?
Use the client’s normal stop or service control, then check whether an unintended manual system proxy remains enabled. If routes or DNS still appear broken, restart the client or system according to its recovery guidance rather than manually deleting routes. On a managed device, ask the administrator before changing network settings.