Map the developer traffic path before changing settings
Developer tools do not all use the same network path. A browser may follow the operating system proxy, while Git reads its own configuration, OpenSSH uses its own connection rules, and Homebrew delegates downloads to tools such as curl, git, or Ruby-based fetchers. This is why enabling the system proxy can make a web page load while git clone, ssh -T [email protected], or brew install still hangs.
A useful troubleshooting model has three layers. First, the Clash or mihomo core must be running and listening on a local inbound port. Second, the developer tool must be configured to send traffic to that port, unless TUN mode is capturing the traffic transparently. Third, the active routing rules must send the destination to a usable policy group. A failure in any layer can look like a generic timeout.
| Tool | Typical default behavior | Recommended control point |
|---|---|---|
| Git over HTTPS | Uses Git configuration and sometimes environment variables | git config or temporary proxy variables |
| Git over SSH | Uses OpenSSH configuration, not Git’s HTTP proxy setting | ~/.ssh/config and a SOCKS-aware command |
| Homebrew | Uses its download tools, Git, and the shell environment | Environment variables, Git settings, and Clash rules |
| Docker or language package managers | Varies by daemon, shell, and package manager | Tool-specific proxy configuration or TUN mode |
In FlClash, Clash Verge Rev, ClashX, or another graphical client, first confirm the active core, the current configuration, and the local port. A common configuration is mixed-port: 7890, which accepts HTTP and SOCKS5 connections on one port. Some clients instead expose separate ports such as 7890 for HTTP and 7891 for SOCKS5. Never assume the port from an online tutorial is correct; inspect the client’s settings or generated YAML.
mixed-port: 7890
mode: rule
allow-lan: false
external-controller: 127.0.0.1:9090
log-level: info
Keep allow-lan: false unless another device genuinely needs to use this computer as a proxy. Binding a proxy to all interfaces can expose it to the local network. If LAN access is required, restrict the listening address with the client’s supported options, set an authentication policy where available, and review firewall rules before testing development traffic.
Configure Git over HTTPS without hiding the failure
GitHub and other code hosts commonly support repository access over HTTPS. This is usually the simplest path to proxy because Git understands an HTTP proxy URL and can use a Clash mixed port for both HTTP and HTTPS requests. The proxy URL describes the local connection from Git to Clash; it does not mean that Git should use the remote website’s URL as a proxy.
For a temporary test, set the proxy only for one command. This keeps the result easy to compare with a direct connection:
git -c http.proxy=http://127.0.0.1:7890 \
clone https://github.com/example/project.git
If the test works, configure Git globally for future HTTPS operations:
git config --global http.proxy http://127.0.0.1:7890
git config --global https.proxy http://127.0.0.1:7890
When the Clash inbound is SOCKS5-only, use a SOCKS URL instead:
git config --global http.proxy socks5h://127.0.0.1:7891
git config --global https.proxy socks5h://127.0.0.1:7891
The socks5h form asks the proxy to resolve the hostname. That can be useful when local DNS resolution is unreliable or when the routing decision should be made using the destination domain. With socks5, hostname resolution may occur locally depending on the library and command path, which can produce inconsistent results.
Inspect and remove stale Git proxy settings
A frequent cause of confusion is an old proxy saved months earlier. Check where the current value comes from:
git config --show-origin --get-regexp 'http\..*proxy|https\..*proxy'
git config --global --list --show-origin | grep -i proxy
If the port belongs to a closed Clash process, Git may report Could not connect to proxy, Connection refused, or wait until its timeout expires. Remove the global setting when you want Git to follow another method:
git config --global --unset http.proxy
git config --global --unset https.proxy
Git can also inherit proxy variables from the shell. These variables are convenient for a short development session, but they affect more commands than Git:
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
git ls-remote https://github.com/example/project.git
Do not set incompatible HTTP and SOCKS values randomly. Use the protocol that the local Clash port actually supports, and keep the variable names consistent with the tool being tested. To return the shell to its previous state, use unset HTTP_PROXY HTTPS_PROXY ALL_PROXY. Lowercase variants such as http_proxy and https_proxy may also be read by Unix tools, so check them when behavior remains unexpected.
Route Git SSH through a SOCKS5 proxy
Git’s http.proxy setting does not affect repositories whose remote starts with git@ or uses an ssh:// URL. Those connections are opened by OpenSSH. When SSH traffic bypasses Clash, port 22 may stall even though HTTPS cloning works. The usual solution is to let OpenSSH create a connection through the local SOCKS5 inbound.
On many systems, the OpenSSH client includes a netcat implementation with SOCKS support. Add a host-specific entry to ~/.ssh/config:
Host github.com
HostName github.com
User git
Port 22
IdentityFile ~/.ssh/id_ed25519
ProxyCommand nc -x 127.0.0.1:7891 -X 5 %h %p
ServerAliveInterval 30
ServerAliveCountMax 3
The -x option identifies the SOCKS proxy, -X 5 selects SOCKS5, and %h and %p expand to the target host and port. The exact nc flags differ between macOS, BSD, and Linux packages. If the command returns an “unknown option” error, check the installed netcat variant rather than changing the SSH key or repository permissions.
Some installations provide a separate proxy helper. For example, a SOCKS-aware utility can be used as the ProxyCommand instead. The important requirement is that the helper supports SOCKS5 and passes the destination hostname and port correctly. Avoid using a plain nc %h %p command: it opens a direct connection and does not involve Clash.
GitHub also provides an SSH endpoint on port 443, which can be useful on networks where outbound port 22 is filtered. Use a separate alias so existing repository URLs remain unchanged:
Host github-ssh
HostName ssh.github.com
User git
Port 443
IdentityFile ~/.ssh/id_ed25519
ProxyCommand nc -x 127.0.0.1:7891 -X 5 %h %p
ServerAliveInterval 30
ServerAliveCountMax 3
Then test the alias directly:
ssh -T git@github-ssh
To use it for a repository, either clone with the alias:
git clone git@github-ssh:example/project.git
or change an existing remote:
git remote set-url origin git@github-ssh:example/project.git
git remote -v
Run SSH in verbose mode when the connection still fails:
ssh -vvv -T git@github-ssh
- Connection refused on
127.0.0.1: Clash is stopped, the port is wrong, or the selected inbound does not support SOCKS5. - Timeout after the proxy connection: The rule selected a failed policy group, the destination is unreachable, or the remote port is filtered.
- Host key warning: Verify the hostname and key fingerprint before accepting a new key. Do not solve an SSH identity problem by disabling host-key checking.
- Permission denied: The network path works, but the SSH key is missing, not loaded, or not authorized for the account.
Make Homebrew and package downloads use the same route
Homebrew operations combine several kinds of traffic. A formula or cask may come from a bottle URL, metadata may be fetched from a repository, and taps may use Git. Consequently, a working Git proxy does not guarantee that brew install will work, and a successful browser download does not prove that Homebrew can reach its bottle host.
Start by testing the shell environment for the current terminal session:
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
brew update
brew install jq
Use a small package for the first test rather than a large SDK or compiler toolchain. Watch the Clash connection panel while the command runs. You should see the relevant domains and the selected policy group. If no connection appears, Homebrew or its underlying process is not inheriting the variables, or the traffic is being handled by another network layer.
Homebrew’s Git-based taps still obey Git’s configuration. Check both the environment and Git values before changing anything:
env | grep -i proxy
git config --show-origin --get-regexp 'http\..*proxy|https\..*proxy'
brew config
Some corporate networks require a custom certificate authority for HTTPS inspection. Do not disable TLS verification globally to bypass certificate errors. Instead, install the organization’s trusted certificate through the operating system or configure the specific tool according to the organization’s security policy. A certificate error and a proxy timeout are different failures and should not be treated with the same workaround.
If Homebrew continues to bypass the explicit proxy, TUN mode may be a better fit. Enable TUN only after confirming that the client has the required administrator or VPN permissions, then test with a command that does not set proxy variables. On macOS and Linux, TUN can capture applications that ignore the system proxy, but it also changes DNS and route behavior. Disable the shell variables during this test to avoid sending TUN-captured traffic into an explicit proxy again.
Write rules for development domains rather than every port
Routing by domain is generally easier to maintain than routing every TCP connection on a port. A minimal rule section might look like this:
rules:
- DOMAIN-SUFFIX,github.com,Developer
- DOMAIN-SUFFIX,githubusercontent.com,Developer
- DOMAIN-SUFFIX,githubassets.com,Developer
- DOMAIN-SUFFIX,homebrew.sh,Developer
- DOMAIN-SUFFIX,brew.sh,Developer
- DOMAIN-SUFFIX,rubygems.org,Developer
- DOMAIN-SUFFIX,pypi.org,Developer
- DOMAIN-SUFFIX,registry.npmjs.org,Developer
- MATCH,DIRECT
Replace Developer with the actual policy group name in the imported configuration. The order matters: Clash evaluates rules from top to bottom. If a broad MATCH,DIRECT rule appears first, later developer-specific rules will never be reached. Likewise, if an earlier rule sends these domains to REJECT or a different group, moving the new rules below it will not fix the result.
Do not add every service domain from an unverified list without review. GitHub, package registries, release CDNs, container registries, and company services can change their hostnames. Begin with the domain shown in the Clash log, add only necessary suffixes, and confirm that the rule does not accidentally route internal company domains through a public proxy. For private repositories, DNS services, artifact servers, and self-hosted Git platforms, use the organization’s approved routing policy.
Verify the path with layered tests
Testing one command at a time makes the result meaningful. First check whether Clash is listening locally:
curl -x http://127.0.0.1:7890 -I --connect-timeout 10 https://github.com
curl --proxy socks5h://127.0.0.1:7891 -I --connect-timeout 10 https://github.com
These tests validate the HTTP and SOCKS paths separately. A successful response proves that the local inbound accepted the request and that the selected policy could reach the destination. It does not prove that Git or SSH uses the same path.
Next test Git without modifying the working tree:
GIT_CURL_VERBOSE=1 git ls-remote https://github.com/example/project.git
For SSH, inspect the effective configuration and then connect verbosely:
ssh -G github-ssh | grep -E 'hostname|port|proxycommand'
ssh -vvv -T git@github-ssh
Finally, test Homebrew and observe the Clash logs at the same time:
brew update
brew fetch --force jq
Interpret the evidence in order. If curl through the local port fails, fix Clash, the port, or the active policy before touching Git. If curl works but git ls-remote fails, inspect Git configuration and inherited variables. If HTTPS Git works but SSH fails, inspect ProxyCommand, the SOCKS port, SSH host aliases, and authentication separately. If all explicit proxy tests work but a tool still bypasses them, enable TUN or configure that tool’s own proxy support.
Developer proxy FAQ
Why does HTTPS cloning work while SSH cloning times out?
Git HTTPS uses Git’s HTTP or SOCKS proxy setting, but SSH is controlled by OpenSSH. Configure a SOCKS5-aware ProxyCommand in ~/.ssh/config, confirm that it points to the correct Clash SOCKS or mixed port, and test the SSH alias with ssh -vvv. If port 22 is filtered, try the code host’s supported SSH-over-443 endpoint rather than changing unrelated Git settings.
Which Clash port should terminal tools use?
Use the port shown by the active client and configuration. A mixed-port such as 7890 can accept HTTP and SOCKS5 requests, while a separate SOCKS port may be required for OpenSSH. Do not copy a port from another computer or assume that the graphical client’s control port is a traffic proxy port; external-controller is for API control, not ordinary web requests.
Should TUN mode replace proxy environment variables?
Not always. Explicit variables are clearer for Git and package managers that support them, while TUN is useful for applications that ignore proxy settings. Use one method while diagnosing a problem. If TUN is enabled, temporarily clear HTTP_PROXY, HTTPS_PROXY, and ALL_PROXY to determine whether the application is already captured transparently.
Why does Homebrew still time out after Git is configured?
Homebrew downloads may use different tools and domains from Git taps. Test the shell proxy variables, run brew config, inspect the Clash connection log, and identify the exact host that fails. Add a narrow domain rule or use TUN when the download process does not inherit the shell environment. Keep TLS verification enabled and solve certificate errors through the trusted certificate configuration instead of disabling security checks.