Why developer command-line tools bypass ordinary proxy settings
When a browser works through Clash but git clone, npm install, or a container build still hangs, the problem is often not the proxy node. Different programs discover proxies in different ways. A browser may follow the operating system’s proxy setting, while a terminal program may look only for environment variables, use its own configuration file, or open connections through a background service that never inherited your shell settings.
That distinction matters when a development machine runs many kinds of network clients. Git can use an HTTPS proxy for an HTTPS remote, but Git over SSH does not automatically use that setting. npm and pip each have their own proxy options. Docker commands talk to a daemon, and that daemon may run outside the environment where you exported HTTPS_PROXY. A successful test in one terminal therefore does not prove that every tool follows the same route.
A practical setup has two layers. Use Mihomo TUN mode in a compatible Clash client to capture network traffic at the operating-system level, then use per-tool proxy settings only when a tool needs an explicit proxy or when you want its behavior to be portable across machines. TUN can reduce the number of commands that need environment variables, but it is not a substitute for understanding which process is making a connection.
This guide uses Clash Verge Rev as an example of a desktop client that can expose Mihomo TUN controls. Labels and permission prompts vary between client versions and operating systems; other Mihomo-based clients may place the same options elsewhere. Before changing routes, confirm that your configuration is active, a proxy group has a working selection, and the client’s Connections or Logs view is available for verification.
Prepare Clash and enable TUN mode safely
First import a Clash-compatible configuration or subscription from a source you trust, select it as the active profile, and choose a usable proxy group. Test that selection before changing system routing. If the selected node is unavailable, TUN may capture traffic successfully while every request still fails at the next hop. Keep subscription links private: they can contain credentials that grant access to your service.
In the client settings, locate the Mihomo or TUN section and enable TUN mode. Depending on the operating system and client build, you may need to install or approve a helper, grant administrator permission, or allow a network extension. Read the operating-system prompt and the client’s documentation before granting access. Do not disable security protections simply to make a permission dialog disappear. If another VPN or proxy client is already operating a tunnel, pause it while testing to avoid competing routes and confusing results.
After enabling TUN, confirm that the client reports the tunnel as active. Then open a test destination and check the Connections view. The useful evidence is not merely that a switch appears enabled: you want to see the destination hostname, the rule or policy that matched it, and the selected proxy group or DIRECT route. A request that does not appear may have been handled by a different interface, a local service, or a daemon outside the captured path.
Start with a narrow, reversible test. Open a fresh terminal and run a simple HTTPS request to a site that should use your selected route. For example:
curl -I https://example.com
Check the response and the matching connection in Clash. A successful response alone is not enough to establish which route was used; correlate it with the client log. If the request is absent, verify that TUN is active, that the application is using the expected network interface, and that the active profile has rules and a valid proxy group. If the request appears as DIRECT unexpectedly, review rule order and the selected mode before adding more configuration.
Use rule mode for a normal development setup unless you have a specific reason to route everything through one group. Rule-based routing lets you send chosen external services through a proxy while leaving local development servers, company resources, and nearby devices on their intended paths. Global mode can be useful as a brief diagnostic comparison, but it can also send internal traffic somewhere it should not go. Restore your normal mode after a test rather than treating Global as a permanent fix.
Route Git and SSH, then verify what the client sees
With TUN active, ordinary Git and SSH connections may be captured without Git-specific proxy variables. Test the exact operation that fails rather than relying on a browser check. For an HTTPS remote, inspect the remote URL and run a small fetch. For an SSH remote, use SSH’s verbose output to see whether name resolution, connection establishment, or authentication is where the attempt stops:
git remote -v
git ls-remote https://github.com/example/project.git
ssh -vT [email protected]
The SSH command is useful because it separates a network failure from a key or account problem. If it reaches the server but reports that public-key authentication failed, changing Clash rules will not repair the SSH key. If it stalls before the handshake, look for the destination in Clash Connections and check the route that was selected. A successful HTTPS fetch does not prove SSH is working: the protocols use different ports and may encounter different policy rules.
If an HTTPS Git remote needs an explicit proxy, configure it deliberately and keep the setting scoped to the intended repository or host when practical. Avoid putting a proxy URL containing a username or password directly into shared project configuration. Git configuration can be inspected and removed, so treat embedded credentials as exposed. For SSH, use a supported SSH proxy method only when needed and understand that the SSH client’s configuration is separate from Git’s HTTPS proxy configuration.
Environment variables are a convenient alternative for tools that honor them. Use the actual local mixed-port value shown in the Clash client; do not assume every profile or client uses the same port. In a POSIX-compatible shell, a temporary test can look like this:
export HTTP_PROXY=http://127.0.0.1:7890
export HTTPS_PROXY=http://127.0.0.1:7890
export ALL_PROXY=socks5h://127.0.0.1:7891
export NO_PROXY=localhost,127.0.0.1,::1,.internal.example
Replace these example ports with the ports configured in your client, and remove variables that your tools do not need. The socks5h scheme asks the proxy to resolve hostnames, while socks5 may resolve them locally; that difference can affect results when DNS policies differ. Many clients accept uppercase names, lowercase names, or both, but behavior is not perfectly consistent. If a tool ignores the variables, check its own documentation rather than repeatedly exporting the same values.
Keep NO_PROXY short and intentional. It is commonly used for loopback addresses, local development endpoints, and explicitly approved private services. A broad entry can bypass the proxy for more destinations than you expect; an overly narrow entry can send local requests into a tunnel and break callbacks or service discovery. After changing it, test both an external hostname and a local endpoint, then inspect the corresponding connections.
Configure npm and pip without hiding the route
For npm, first run a normal package operation with TUN enabled and observe whether the registry request appears in Clash. If it does, and the result is stable, a global npm proxy setting may be unnecessary. If your environment requires explicit proxy configuration, use npm’s supported configuration and verify the registry URL and proxy values with the appropriate configuration commands. Avoid committing user-specific proxy settings to a project’s .npmrc, especially when the setting contains credentials or a machine-specific loopback port.
Be cautious when diagnosing npm failures from a single error message. A timeout can indicate a routing issue, but a package-not-found response, an expired registry token, a certificate error, or a lockfile conflict points elsewhere. Check whether the failure affects all packages or only one private scope. A public registry request and a private registry request may target different hostnames and follow different authentication and routing rules. Review the actual destination in the Clash log rather than adding a catch-all rule based on a guess.
pip has similar distinctions. A package index, a wheel hosted on a separate content domain, and an internal package server may not share one hostname. A request can reach the index successfully and then fail while downloading a file from another host. With TUN, observe the complete sequence of connections. With an explicit pip proxy, use the configuration mechanism supported by your pip version, keep secrets out of shell history and shared files, and avoid setting a permanent global proxy if only one environment needs it.
When a command fails, compare a direct diagnostic request with the package tool’s own behavior. For example, a request to the configured package index can help establish basic connectivity, while a verbose package install can reveal which host actually failed. Do not treat a successful request to a homepage as proof that every package download domain is reachable. Providers change content delivery infrastructure, and an old list of registry hostnames may no longer describe the connections your installation makes today.
Also check certificate handling before weakening TLS verification. A corporate inspection certificate, an outdated system trust store, or a custom Python environment can produce certificate failures even when routing is correct. Do not use insecure flags as a routine proxy workaround. Identify whether the failing connection is reaching the intended endpoint, then follow your organization’s approved certificate and package-source guidance.
Understand Docker’s separate daemon and container routes
Docker is a common source of confusion because the command you type and the process that downloads images are not always the same process. docker pull sends a request to the Docker daemon; the daemon performs registry access. Exporting proxy variables in your interactive shell may affect the Docker CLI but not the daemon. Docker Desktop, a Linux service, and a remote Docker context can each have different networking boundaries.
First identify where the daemon runs. If it is Docker Desktop, inspect the desktop application’s networking and proxy settings as well as Clash Connections. If the daemon is a Linux service, check the service’s supported environment configuration and restart behavior according to your system’s administration practices. If the CLI is connected to a remote context, the traffic leaves from the remote host, not necessarily from the computer where you launched the command. TUN on your laptop cannot automatically capture traffic generated by a daemon on another machine.
Test a small image pull and look for the registry and content delivery connections. A registry may redirect downloads to another hostname, so a rule that matches only the first endpoint might not cover the full transfer. If the daemon is local but its requests do not appear in the TUN log, check whether the client excludes that process or interface, whether Docker Desktop uses a separate virtual network, and whether your operating system requires an additional route or permission. Change one setting at a time so you can identify what made the difference.
Container traffic has another boundary. A process inside a container may use the container’s DNS, bridge network, and proxy environment, which can differ from the host’s. Host-level TUN may capture some container traffic, but the result depends on the platform and network architecture. If a build needs an explicit proxy, pass it through the supported Docker build or daemon configuration mechanism, and do not bake secrets into image layers. Keep build-time credentials in an approved secret mechanism and remove them from the final image.
Do not route every container through a proxy by default. Development containers often need access to local databases, test services, package mirrors, and private registries. Decide which traffic belongs on a proxy route, which should remain local, and which must follow company policy. Then test from the same context that fails: host shell, container shell, Docker Desktop daemon, or remote engine. A successful host-side curl cannot validate a remote daemon’s access to a registry.
Keep local services and private networks on the right route
A developer workstation is not only an internet client. It may run a web server on localhost, connect to a test database on a private subnet, reach a company Git server, or use a callback from a browser to a local application. If these destinations are sent through a proxy, requests can fail, expose internal hostnames to an external service, or take an unintended path around network controls.
Begin with the services you use every day. List loopback hosts, local domain suffixes, private address ranges, and approved corporate domains that must remain DIRECT or follow a specific company route. Add or adjust rules only in the configuration layer you control, and place specific exceptions before broad matching rules. A broad private-network bypass may be convenient at home but inappropriate on a managed workstation; follow organizational policy rather than assuming that every private address is trusted.
DNS behavior deserves special attention. TUN and fake-IP modes can change how a hostname is resolved or represented to applications. If a local service works by IP address but not by name, compare the resolver path, the hostname used by the client, and the rule matched in Clash. Do not permanently hard-code a changing service address just to make one test pass. For private DNS zones, use the resolver and routing behavior approved for that network, and verify that external queries are not leaking internal names.
Use a small validation checklist after a profile change: a public HTTPS request should follow its intended proxy rule; a local development endpoint should remain reachable; a private company service should follow its approved path; Git over HTTPS and SSH should be tested separately; and Docker should be tested from the daemon that actually performs the download. Save the results and the relevant rule names, not screenshots containing subscription URLs, tokens, or other secrets.
If a failure starts after changing a profile, revert that one change before adding another exception. Clear application connection pools or restart a tool only when necessary; long-lived clients may keep existing sockets after a routing change. When reporting a problem, include the client and operating-system versions, the relevant rule result, and a redacted error message. Never publish credentials, full subscription links, private hostnames, or unredacted network logs.
Frequently asked questions
Does TUN mode make proxy environment variables unnecessary?
Not always. TUN can capture many host connections without per-tool configuration, which is useful when applications ignore system proxy settings. However, some tools, daemons, remote contexts, virtual machines, and container networks may use a different route. Start with TUN, confirm the connection appears in Clash, and add explicit variables only for a process that needs them.
Why does Git over HTTPS work while Git over SSH fails?
They use different protocols and often different ports. Git’s HTTPS proxy setting does not automatically configure the SSH client. Check the SSH client’s verbose output and the matching Clash connection. If the connection reaches the server but authentication fails, investigate your SSH key or account; if it never establishes a network connection, inspect routing and any required SSH proxy configuration.
Why does Docker ignore the proxy exported in my shell?
The Docker daemon usually performs image downloads, and it may not inherit the interactive shell’s environment. It could also run in Docker Desktop, on a remote host, or in a separately managed service. Identify the daemon’s location and configure or route that process using the method supported by its environment. Then verify the registry traffic from the daemon itself.
What should I check if localhost stops working after enabling TUN?
Check the active rules, loopback exclusions, and NO_PROXY values, then confirm that the application is connecting to the expected local address and port. Avoid broad bypass rules until you know which destination needs an exception. A local callback may use a hostname or IPv6 address rather than 127.0.0.1, so test the exact address shown in the application or Clash log.
Some command-line proxy wrappers require repetitive per-tool settings, while a system-wide tunnel can be difficult to troubleshoot if it hides which process or rule handled a request. A measured Clash setup gives developers a more observable middle ground: Mihomo TUN can cover compatible traffic, explicit settings remain available for tools and daemons that need them, and rule-based routing can keep localhost and approved private services on their intended paths. If you want to compare clients and choose the one that fits your operating system, start with the download page.