预计阅读 9 分钟

系统代理开了却没生效?浏览器与终端两条线分别排查

开着系统代理开关,访问却还是走的直连,或者浏览器通了终端不通、终端通了浏览器又不通——这类问题的根源多半不在 Clash 本身,而在系统代理这层"转发"有没有真的接上。本文把浏览器链路和终端链路拆开讲,按检查顺序逐项排查。

先把"系统代理"拆成两条链路

"系统代理"这个词容易让人以为是一个统一开关,实际上操作系统层面的代理设置只对遵守系统代理配置的应用生效,而"遵守"这件事分成两条完全独立的链路:

  • 浏览器链路:主流浏览器(Chrome、Edge、Firefox 等)在 Windows/macOS 上默认读取系统的代理设置项,这条链路由操作系统的网络设置面板控制。
  • 终端/命令行链路:终端里的 curlgit、包管理器等工具不认系统面板,它们认的是 http_proxyhttps_proxy 这类环境变量,系统代理开关对它们完全不起作用。

这就是为什么很多人反馈"Clash 开着但没生效"——其实生效范围本身就不覆盖终端,而问题恰恰出在终端这条链路没配。反过来也有人抱怨终端能用、浏览器却直连,这多半是系统代理设置项本身没被正确写入,或者被例外列表挡住了。

Clash 系客户端启动后本身只做两件事:在本机监听一个代理端口(HTTP/SOCKS/混合端口),按规则把流量分发到不同节点。至于系统里的其他程序要不要把流量送到这个端口,取决于系统代理设置或环境变量是否正确配置——这一步是操作系统的职责,不是 Clash 内核的职责。

第一步:确认 Clash 真的在监听

在怀疑系统代理设置或环境变量之前,先确认端口本身是通的,这一步能排掉一半的"假性无效"。

  1. 打开客户端的连接/端口设置页,记下当前的 HTTP 端口(常见默认值 7890)和是否启用了混合端口。
  2. 用命令行直接测试这个端口,不经过系统代理开关,单纯验证监听是否存在:
    curl -x http://127.0.0.1:7890 https://www.google.com -I
    能拿到 HTTP 响应头(哪怕是 301/302)说明端口本身没问题,问题在系统代理这一层没接上;如果直接报连接被拒绝,说明客户端没启动或端口被改过,先解决这一步再往下看。
  3. Windows 下可用 netstat -ano | findstr 7890、macOS/Linux 下用 lsof -i :7890 确认端口的占用进程确实是 Clash,而不是被别的程序抢占。
端口类型常见默认值典型用途
HTTP 端口7890浏览器系统代理、大部分终端工具
SOCKS 端口7891部分要求 SOCKS5 的客户端
混合端口(mixed-port)视配置而定同一端口同时接受 HTTP 与 SOCKS 请求
控制面板端口9090RESTful API,与代理转发无关

浏览器这条线:系统代理为什么没吃到

浏览器链路失效常见于三个环节,按顺序检查:

  1. 系统代理开关没真正打开——客户端里的"设置为系统代理"是个联动开关,有些版本重启后不会自动恢复上次状态,需要手动确认一次当前是否为开启状态,而不是凭记忆判断。
  2. 浏览器有自己的独立代理设置——多数浏览器默认跟随系统,但如果之前手动改过"手动配置代理"或安装过代理管理类扩展,浏览器会优先读取自己的配置而忽略系统层设置,这种情况下把浏览器代理模式改回"系统代理"或直接停用相关扩展。
  3. 企业/教育网络的组策略覆盖——部分办公电脑由组策略统一管理网络设置,系统代理项即使显示已勾选,实际浏览行为仍受策略层覆盖,这种环境下建议直接用 TUN 模式绕开系统代理这层设置(见文末)。

浏览器无痕/隐私窗口有时会单独维护一套网络设置缓存,普通窗口生效了不代表无痕窗口同步生效,遇到"部分窗口能用部分不能用"先重开一次无痕窗口再判断。

终端这条线:环境变量和 shell 配置

终端不读系统代理面板,它认的是环境变量,最常用的几个是 http_proxyhttps_proxyall_proxy(小写规范,大写形式各工具兼容性不一)。临时测试可以直接在当前终端会话里导出:

export http_proxy="http://127.0.0.1:7890"
export https_proxy="http://127.0.0.1:7890"
export all_proxy="socks5://127.0.0.1:7891"

这种写法只对当前终端窗口生效,关闭窗口就失效。如果想让每次开终端都自动生效,要把这几行写进 shell 的启动配置文件——bash 用户写 ~/.bashrc~/.bash_profile,zsh 用户(macOS 默认 shell)写 ~/.zshrc,写完执行 source ~/.zshrc 让当前窗口立即读取,不用重启终端。

常见的三个坑:

  • 写错了配置文件——macOS 默认 shell 早已切换为 zsh,很多人还在照着老教程改 .bashrc,结果新开的终端根本不会读到。用 echo $SHELL 先确认当前用的是哪个 shell。
  • 端口号和实际不一致——客户端换过端口、重装过配置文件后忘记同步更新环境变量里写死的端口号,这类问题只在终端出现,浏览器因为跟随系统代理设置反而是正常的,两边表现不一致时先比对端口号。
  • 某些工具单独读取自己的配置项——比如 Git 会优先读取 git config --global http.proxy 里单独设置的代理地址,即使环境变量对了,Git 仍按自己的配置项走,需要额外执行:
    git config --global http.proxy http://127.0.0.1:7890
    git config --global https.proxy http://127.0.0.1:7890

配好环境变量后,用 curl -v https://ipinfo.io/ip 输出的 IP 是否变成节点所在地区的 IP 来验证,而不是只看命令是否报错——报错为空不代表真的走了代理,有可能是直连也成功访问了。

PAC 残留与代理例外名单

如果之前用过基于 PAC 文件的代理工具(自动配置脚本模式),卸载或换用 Clash 之后,系统里可能残留着旧的 PAC 地址没有清空,导致系统代理面板显示的是"使用设置脚本"而不是手动指定的 IP+端口,这种残留优先级往往比手动代理更高,表现就是开了系统代理却依旧直连或访问异常。检查方法:

  1. Windows:打开"设置 → 网络和 Internet → 代理",看"使用设置脚本"是否被启用,如果是,先关掉再单独开启"手动设置代理"。
  2. macOS:系统设置 → 网络 → 对应网络服务的详细信息 → 代理,检查"自动代理配置"是否勾选了旧的 PAC 地址,同时确认"网页代理(HTTP)"和"安全网页代理(HTTPS)"这两项分别填的是 Clash 的端口。

另一个容易被忽略的地方是代理例外列表(no_proxy / bypass list)。系统代理设置里通常有一栏"对这些地址不使用代理服务器",默认会包含 localhost127.* 等本地地址,这是正常的,但有些安装包或旧配置会往这里塞进大段通配规则,导致大量正常站点被划进例外名单,访问时全部走直连而不经过代理。检查时重点看这个例外栏是不是被写入了超出预期的域名段,终端里对应的环境变量是 no_proxy,同样值得单独检查一遍:

echo $no_proxy

no_proxy 里如果写了 * 或者过宽的通配符(比如整个顶级域),会让终端代理形同虚设,所有请求都被判定为例外走直连,这种写法建议直接清空重写,只保留必要的本机地址。

排查顺序清单与兜底方案

把上面的内容压缩成一份可以照着走的顺序表,遇到"系统代理开了却没生效"从上到下逐项核对:

  1. curl -x 直接测端口,确认 Clash 本身在监听且端口号正确。
  2. 检查客户端的"设置为系统代理"开关是否真的处于开启状态。
  3. 检查浏览器是否被单独设置过手动代理或装了代理管理扩展,统一改回跟随系统。
  4. 检查系统代理面板是否残留旧的 PAC 脚本地址,清空后手动指定 IP 与端口。
  5. 检查系统代理例外名单与终端 no_proxy 变量,清理过宽的通配规则。
  6. 终端环境变量按当前 shell(bash/zsh)写入对应配置文件,端口号与客户端实际设置保持一致。
  7. 单独检查 Git 等自带代理配置项的工具,避免它们读取了过期的旧地址。

如果排查完还是有个别应用死活不认系统代理设置或环境变量——这类情况并不少见,一些独立进程的程序压根不检查系统代理面板,也不读 shell 环境变量,只认自己写死的直连逻辑。遇到这种"死不听话"的应用,更省事的做法是切到 TUN 模式:客户端在系统网络层建一张虚拟网卡,所有出网流量在网络层被统一接管,不再依赖某个应用是否主动"配合"系统代理设置,浏览器、终端、其他独立进程的流量会被一并处理。TUN 模式的接管范围更彻底,但对 DNS 处理、网卡权限的要求也更高,配置上比系统代理多一步授权,具体开启方式可以在教程页里查看分平台的操作步骤。

下载 Clash 客户端

先确认客户端本身正常监听,再逐项核对系统代理与环境变量,是排查这类问题最省时间的顺序。

下载Clash