系统代理不生效排查
浏览器扩展抢占、终端不读系统代理、环境变量缺失,这几类原因分开定位,各自给出可验证的修复方法。
先分清:代理开关、应用入口与规则出口
Clash 客户端显示“系统代理已开启”,通常只说明客户端尝试把本地代理地址写入操作系统设置。它不等于所有程序已经进入内核,更不等于每个请求都会使用远端节点。浏览器可能读取系统设置,也可能被扩展接管;终端中的 curl、Git 和包管理器则可能使用各自的环境变量或配置文件。
一次请求需要依次通过三个环节:应用连接本地监听端口、内核按规则选择策略、选中的出口完成连接。排查时先固定测试网址和端口,再查看客户端“连接”页面或日志。不要同时换节点、改 DNS、开 TUN,否则无法判断是哪项修改起了作用。
| 现象 | 优先检查 | 验证依据 |
|---|---|---|
| 浏览器正常,终端失败 | 终端代理变量与工具配置 | 显式指定代理的 curl 是否成功 |
| 终端正常,浏览器失败 | 扩展、浏览器代理设置、启动参数 | 停用代理扩展后重新请求 |
| 浏览器与终端都失败 | 本地监听、内核状态、出口连接 | 端口检查与内核日志 |
| 连接出现,但显示 DIRECT | 规则模式、命中规则、策略组 | 连接详情中的规则与完整策略链 |
第一步:确认内核确实监听本地端口
区分 mixed-port、port 与 socks-port
mihomo 配置中的 mixed-port 可以在同一端口接受 HTTP 和 SOCKS 代理请求;port 是 HTTP 代理入口;socks-port 是 SOCKS 入口。把 HTTP 请求发到只支持 SOCKS 的端口,可能得到协议错误或连接中断。图形客户端还可能覆盖订阅中的端口,因此运行时设置比订阅原文更有参考价值。
# mihomo 本地入口示例;不要直接覆盖整份订阅配置
mixed-port: 7890
allow-lan: false
mode: rule
同一台电脑上的浏览器和终端不需要开启 allow-lan。它用于控制局域网访问,不负责让本机应用读取系统代理。排查本机连接时使用明确的 IPv4 回环地址 127.0.0.1,可以避免 localhost 被解析到 ::1、但内核只监听 IPv4 所带来的歧义。
检查监听,再发送显式代理请求
# Windows PowerShell:查看 7890 的监听状态
Get-NetTCPConnection -LocalPort 7890 -State Listen
# Linux:查看 TCP 监听
ss -lntp 'sport = :7890'
# macOS:查看 TCP 监听与进程
lsof -nP -iTCP:7890 -sTCP:LISTEN
选择自己系统对应的一条命令即可。若没有监听结果,先处理客户端内核未启动、配置解析失败或端口被占用的问题。若显示监听,仍需核对所属进程;其他软件也可能占据 7890。
# macOS / Linux
curl -q -v --noproxy "" --proxy http://127.0.0.1:7890 \
--connect-timeout 7 --max-time 20 -I https://example.com/
# Windows PowerShell:明确使用 curl.exe
curl.exe -q -v --noproxy "" --proxy http://127.0.0.1:7890 --connect-timeout 7 --max-time 20 -I https://example.com/
-q 放在首个参数位置,用来跳过默认 curl 配置文件;--noproxy "" 在支持空参数传递的 shell 中清空绕过列表;--proxy 明确指定入口。旧版 Windows PowerShell 对空字符串参数的传递存在差异,若结果仍显示绕过代理,可先临时移除当前会话的 NO_PROXY,再重试。
看到 Connected to 127.0.0.1,只证明本地代理入口可达;HTTPS 请求继续出现 200 Connection established,说明 HTTP CONNECT 隧道已经建立。还要看随后目标站的响应和内核连接记录。这里测试的是 example.com,成功不能推导出所有目标站都能访问。
第二步:浏览器单独排查系统设置与扩展
Chrome、Edge:先排除扩展接管
- 打开 Chrome 的
chrome://extensions/或 Edge 的edge://extensions/,暂时停用所有管理代理、PAC 或网络切换的扩展。 - Chrome 进入「设置」→「系统」→「打开您计算机的代理设置」;Edge 进入「设置」→「系统和性能」→「系统」查找代理入口。不同版本的文字和分组可能略有不同。
- 在系统代理页核对地址、端口和绕过列表。若系统使用 PAC,检查当前生效的是 PAC 还是手动代理;不要仅凭其中某个开关判断实际路径。
- 完全退出浏览器后重新启动,再访问测试网址,同时观察客户端的连接记录。
Windows 11 的系统入口是「设置」→「网络和 Internet」→「代理」。macOS 的入口是「系统设置」→「网络」→当前网络服务→「详细信息」→「代理」。手动 HTTP 代理与安全 Web 代理可能是两个项目,使用 HTTPS 网站测试时也要核对对应设置。
如果设置页提示代理由扩展或组织管理,应先查明管理来源。企业策略和浏览器启动参数可能覆盖普通设置;反复切换 Clash 的系统代理按钮通常不能消除这种覆盖。隐私窗口也不是可靠的隔离试验,因为某些扩展获得了在隐私窗口运行的权限。
Firefox:检查是否使用独立代理
桌面版 Firefox 进入「设置」→「常规」→页面底部「网络设置」→「设置」。选择“使用系统代理设置”后,才沿用操作系统代理;若选择“手动配置代理”或“自动代理配置 URL”,它使用的是浏览器自己的配置。
- 手动 HTTP 代理:地址填写
127.0.0.1,端口填写实际 HTTP 或混合端口;同时核对 HTTPS 代理项。 - 手动 SOCKS:选择 SOCKS v5,端口必须是 SOCKS 或混合端口;需要由代理处理目标域名时,核对 SOCKS v5 的代理 DNS 选项。
- “不使用代理”列表:检查测试域名及其后缀是否在其中,避免把绕过规则误判为客户端故障。
第三步:给终端设置当前会话的代理变量
终端窗口本身不负责代理网络请求,真正发起连接的是窗口里的程序。许多命令行工具不会自动读取桌面系统代理。显式代理测试成功、普通命令失败时,优先补齐该工具支持的环境变量,而不是直接更换节点。
macOS 与 Linux:先临时 export
export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
export no_proxy=localhost,127.0.0.1,::1
curl -v --connect-timeout 7 --max-time 20 -I https://example.com/
https_proxy 的变量名表示它用于 HTTPS 目标,并不要求变量值使用 https://。常见 Clash 本地 HTTP 代理通过 HTTP CONNECT 承载 HTTPS,所以这里仍写 http://127.0.0.1:7890。随意改成 https:// 会让工具尝试与本地代理建立 TLS,可能因监听端不支持而失败。
这些变量只影响当前 shell 及之后启动的子进程。确认有效后,再按实际 shell 写入 ~/.zshrc 或 ~/.bashrc。不要一次写入多个启动文件;从桌面启动的 IDE 也未必读取这些文件,需要在 IDE 的环境或终端设置中另行确认。
Windows PowerShell:使用会话环境变量
$env:http_proxy = "http://127.0.0.1:7890"
$env:https_proxy = "http://127.0.0.1:7890"
$env:no_proxy = "localhost,127.0.0.1,::1"
curl.exe -v --connect-timeout 7 --max-time 20 -I https://example.com/
在 Windows PowerShell 5.1 中,curl 可能是 Invoke-WebRequest 的别名。使用 curl.exe 可以明确运行 curl,避免把两套工具的参数和代理行为混在一起。会话变量不会追溯修改已经运行的程序;启动新进程时才会继承当前环境。
需要 SOCKS 时,明确 DNS 解析位置
curl -q -v --noproxy "" --proxy socks5h://127.0.0.1:7890 \
--connect-timeout 7 --max-time 20 -I https://example.com/
在 curl 中,socks5:// 通常由本地解析目标域名;socks5h:// 将目标域名交给 SOCKS 代理处理。两者的差异有助于定位 DNS 问题,但其他工具不一定支持相同的 URL 写法。设置 ALL_PROXY 前应先查该工具文档,不能假定它对所有程序都有效。
第四步:检查 NO_PROXY 与工具自己的配置
环境变量正确仍然直连,常见原因是绕过列表或工具级设置。NO_PROXY 与 no_proxy 用于指定不经过代理的主机,不同工具对大小写、域名后缀和 CIDR 的支持不完全相同。尤其要检查是否存在 *,它在许多工具中表示绕过全部目标。
# macOS / Linux:仅在本机查看代理变量
env | grep -i proxy
# Windows PowerShell
Get-ChildItem Env: | Where-Object Name -Match 'proxy'
# 查看 Git 配置来源,包括系统、全局和当前仓库
git config --show-origin --get-regexp '.*proxy.*'
Git 的 http.proxy、按 URL 匹配的代理配置,或者包管理器自己的代理项,可能让同一终端里的两个命令走不同路径。如果 Git 指向旧的 127.0.0.1:7891,而当前客户端只监听 7890,就会出现 curl 成功、Git 失败的组合。
- Git:结合
--show-origin找到具体配置文件和作用域,仅修改已确认的错误项。仓库级配置可能覆盖全局配置。 - npm:使用
npm config get proxy和npm config get https-proxy查看工具自己的入口,同时检查项目内的.npmrc。 - WSL 与容器:其中的
127.0.0.1通常指向各自网络环境,不应默认等于 Windows 或宿主机。WSL 网络模式与容器网络配置会改变可达路径。
如果必须让虚拟机或容器访问宿主机代理,需要核对宿主机可达地址、客户端监听范围及防火墙规则。只向必要的本地网络开放,不要为了临时排查把代理端口暴露到公网。
第五步:入口正常后,再检查规则、DNS 与 TUN
有连接记录,却没有使用预期节点
先在客户端连接详情中找到测试域名,核对命中的规则和策略链。在规则模式下,DIRECT 表示内核按规则选择直连,不代表应用绕过了内核。如果策略组当前选中了直连,或目标命中了直连规则,单纯打开系统代理不会改变这一结果。
可在记录原设置后,短暂改用全局模式并明确选择一个已知可用的代理出口,对同一网址重复测试。若全局模式成功、规则模式失败,应回到规则顺序、域名匹配和策略组选项排查,完成后恢复原模式。不要把全局测试的结果直接当成长期配置建议。
根据报错所在阶段缩小范围
| 观察结果 | 含义与下一步 |
|---|---|
| 连接 127.0.0.1:7890 被拒绝 | 优先检查本地监听、进程退出和端口填写,不先调整远端节点。 |
| 本地连接建立,随后超时 | 结合内核日志检查节点连接、目标 DNS 和出口;仅凭超时不能确定是哪一层。 |
| 日志显示目标域名解析失败 | 核对内核 DNS 配置、上游解析器可达性,以及 SOCKS 的解析位置。 |
| 目标返回 HTTP 403 或 429 | 请求可能已到达目标服务,需检查访问策略或频率限制,不等同于本地代理未生效。 |
什么时候才需要 TUN 模式
TUN 通过虚拟网卡和路由接管符合条件的流量,适合无法配置代理、也不读取系统代理的程序。它不是修复错误端口和失效节点的替代方案,也不意味着接管后所有连接都使用远端节点;最终出口仍取决于规则。
如果只是 curl 缺少环境变量,先修正变量通常更容易验证。确实需要 TUN 时,再按客户端要求安装服务或授予管理员权限,核对路由和 DNS,并留意其他 VPN 的冲突。比较系统代理与 TUN 的差异时,一次只改变一个接管入口,避免两套路径同时生效而掩盖原因。
恢复设置与最终验收
验收应覆盖浏览器、显式代理 curl、普通 curl 三项,并对同一个目标检查连接记录。浏览器成功而普通 curl 失败,继续查终端配置;显式代理 curl 也失败,则回到监听和内核日志。不要仅以客户端开关颜色或节点延迟数字作为完成依据。
- 记录最终端口、代理入口类型和生效配置来源,例如“混合端口 7890,PowerShell 当前会话环境变量”。
- 恢复临时关闭的必要扩展,逐一启用并复测;发生回退时即可定位冲突来源。
- 清理调试期间添加的全局模式、宽泛绕过项和重复代理变量,避免下次启动出现不同结果。
# macOS / Linux:仅当这些变量是本次临时设置时清理
unset http_proxy https_proxy all_proxy no_proxy
# Windows PowerShell:清理本次会话中的临时项
Remove-Item Env:http_proxy, Env:https_proxy, Env:all_proxy, Env:no_proxy -ErrorAction SilentlyContinue
清理命令不会撤销启动文件或工具配置中的持久化设置。若已写入配置文件,还需修改对应文件。关闭客户端后再次检查系统代理是否恢复,避免系统仍指向一个已经停止监听的本地端口。