Linux 上把 Clash 用顺:开启代理、切换节点、查询出口、脚本与日常工作流
最近我在一台 Ubuntu 服务器上折腾 Clash(准确说是 Mihomo/Clash Meta 这一类内核),本来只是想解决一个很简单的问题:让服务器稳定走代理,然后安装工具、切换节点、测试出口国家,必要时再开 TUN 做全局接管。
结果一路踩坑:
- Clash 明明启动了,但
ping google.com死活不通; curl --proxy能访问 Google,普通终端命令却还是不走代理;- API 能查到节点列表,但切换节点时报
proxy not exist; - 交互式切换每次手敲 JSON 太麻烦;
- 开始装 Claude Code 时,脚本不是卡住,就是拿到 HTML 页面;
- 最后才发现:很多问题根本不是“代理坏了”,而是“代理方式没搞明白”。
这篇文章把我这次在 Linux 上把 Clash 用顺的过程完整记录下来,重点包括:
- 如何在终端里真正让命令走代理
- 如何查询当前节点与切换节点
- 如何查询当前出口国家/地区
- 如何写一个交互式切换脚本
- 如何开启 TUN,以及什么时候该用、什么时候不该用
如果你也在 Linux 服务器、远程开发、AI 工具、GitHub、安装脚本这些场景里折腾代理,希望这篇能帮你少踩一些坑。
关键结论先行
在 Linux 终端里使用 Clash 时,“Clash 已经在监听端口”并不等同于“所有命令都会走代理”。通常需要同时满足:你配置了命令所使用的代理(环境变量或显式 --proxy),以及 Clash 的端口/API 可用。
本文会用同一套可复现流程,把“代理端口是否可用”“当前命令是否走代理”“当前出口是否符合预期”逐层验证清楚。
graph LR
Cmd[命令/工具] -->|"读取环境变量或显式指定代理"| LocalProxy[本地代理端口<br/>7890/7891]
LocalProxy --> Clash[Clash/Mihomo]
Clash --> Target[目标站点/接口]
前置条件
- 你已经启动了 Clash/Mihomo,并且本地端口可监听:
7890(HTTP 代理)7891(SOCKS5 代理)9090(external controller / API)
- 你的环境里可用这些工具(至少其中部分):
curljq(用于解析 JSON)
- 下文示例默认使用策略组名
🔰 选择节点(如果你的组名不同,需要替换对应字段)。
可复现步骤(建议顺序)
- 先验证端口与服务是否正常(例如确认
7890/7891/9090在监听)。 - 在当前 shell 导出代理环境变量(或在单次命令中显式指定
--proxy)。 - 用带代理的
curl验证“代理端口是否真的能用”。 - 通过 API 查询当前节点与节点列表(读取
/proxies返回的all与now)。 - 通过 API 切换节点,并再次查询
now进行确认。 - 用带代理的请求查询出口 IP/国家等信息,避免仅凭节点名判断。
- 只有在需要更接近“系统全局接管”的场景,才考虑启用 TUN。
常见误解与纠正(本文后续展开)
常见的误解是:用 ping 去验证 HTTP/SOCKS 代理链路是否可用。ping 测的是 ICMP,并不会自动通过你配置的代理端口转发流量。
一、先搞明白:Clash 启动了,不等于所有命令都在走代理
我一开始遇到的一个常见误区是:Clash 已经在监听 7890/7891 端口了,那系统应该已经“翻过去了”吧?
结果现实是:
1 | ping www.google.com |
但另一边:
1 | curl -I --proxy http://127.0.0.1:7890 https://www.google.com |
这说明了一个关键事实:
你现在开的,只是本地 HTTP/SOCKS 代理端口,不是系统全局代理。
也就是说:
127.0.0.1:7890是 HTTP 代理端口127.0.0.1:7891是 SOCKS5 代理端口- 程序只有“显式使用这些代理端口”时,流量才会走 Clash
- 普通终端命令不会凭空自动走 7890/7891
这也是为什么:
curl --proxy ...能通ping还是不通apt、pip、git是否走代理,要看它们有没有读到代理环境变量
二、终端里如何真正开启代理
1. 当前 shell 临时生效
常用的做法是在当前终端导出环境变量:
1 | export http_proxy=http://127.0.0.1:7890 |
设置完之后,很多命令就会直接走代理,例如:
1 | curl https://www.google.com -I |
2. 永久写入 ~/.bashrc
如果你希望每次打开终端都自动带上代理,可以写入:
1 | cat >> ~/.bashrc <<'EOF' |
三、为什么开了代理,ping google.com 还是不通?
结论其实很简单:
ping测的是 ICMP,不会自动通过你这个 HTTP/SOCKS 代理端口。
所以:
curl、git、pip这类支持代理的应用,能走 7890/7891ping这种系统级网络探测工具,不会因为你设置了 HTTP 代理就自动穿过去
因此,验证 Clash 是否真的工作,不要优先用 ping,而应该优先用:
1 | curl -I --proxy http://127.0.0.1:7890 https://www.google.com |
如果这两个能通,说明:
- 节点是通的
- Clash 内核是正常工作的
- 只是你的系统流量还没有全局接管
验证方式对照
| 你想确认的事情 | 更合适的验证方式 | 说明 |
|---|---|---|
| 代理端口是否可用 | curl --proxy http://127.0.0.1:7890 ... / curl --socks5-hostname 127.0.0.1:7891 ... |
直接把请求交给 Clash 本地端口处理 |
| 当前命令是否“默认走代理” | 看环境变量是否存在,或检查命令是否显式带了代理参数 | 端口存在不代表每个命令都会自动走代理 |
| 当前节点/策略组状态 | 调用 /proxies 并读取 all / now |
这属于 API/控制层验证 |
| 当前出口国家/地区 | 使用带代理的请求查询出口 IP(例如 api.ip.sb/geoip) |
避免只凭节点名猜测 |
四、如何查询当前节点与节点列表
我的 Clash 开了 external controller,监听在:
1 | 127.0.0.1:9090 |
所以可以直接通过 API 查询策略组和节点。
1. 查看某个组当前的节点信息
例如我常用的策略组叫 🔰 选择节点:
1 | curl -s http://127.0.0.1:9090/proxies | jq '.proxies["🔰 选择节点"]' |
输出类似这样:
1 | { |
这里需要关注两个字段:
all:这个组里所有可选节点now:当前正在使用的节点
2. 只看当前节点
1 | curl -s http://127.0.0.1:9090/proxies | jq -r '.proxies["🔰 选择节点"].now' |
五、为什么切换节点时报 proxy not exist
我当时第一次切节点时,写的是:
1 | curl -s -X PUT 'http://127.0.0.1:9090/proxies/%F0%9F%94%B0%20%E9%80%89%E6%8B%A9%E8%8A%82%E7%82%B9' -H 'Content-Type: application/json' -d '{"name":"美国Z02"}' |
结果返回:
1 | {"message":"Selector update error: proxy not exist"} |
后来才反应过来:
切换时的
name必须和节点完整名称完全一致。
也就是说,如果节点列表里是:
1 | 🇺🇲 美国Z02 |
那你就必须写:
1 | curl -s -X PUT 'http://127.0.0.1:9090/proxies/%F0%9F%94%B0%20%E9%80%89%E6%8B%A9%E8%8A%82%E7%82%B9' -H 'Content-Type: application/json' -d '{"name":"🇺🇲 美国Z02"}' |
切换成功后,再看当前节点:
1 | curl -s http://127.0.0.1:9090/proxies | jq -r '.proxies["🔰 选择节点"].now' |
六、如何查询当前节点位于哪个国家
节点名字写“日本”“美国”不一定可靠,通常更可靠的方式是:
让请求显式走当前代理,然后查出口 IP 的地理信息。
我这里用的是 ip.sb:
1 | curl -s --proxy http://127.0.0.1:7890 https://api.ip.sb/geoip | jq |
如果只想看关键信息:
1 | curl -s --proxy http://127.0.0.1:7890 https://api.ip.sb/geoip | jq -r '"IP: \(.ip)\n国家: \(.country)\n地区: \(.region)\n城市: \(.city)\n组织: \(.organization)"' |
这样你就能很直观地看到:
- 当前出口 IP
- 国家
- 地区
- 城市
- ASN / 组织
这比“看节点名猜国家”靠谱得多。
七、一个可复用的节点管理脚本
每次手敲 curl + jq + PUT + JSON 太累,所以我后来写了一个脚本,支持:
- 列出节点
- 显示当前节点
- 模糊关键词切换
- 精确名称切换
- 查询当前出口国家
保存为 clash-node.sh:
1 |
|
赋予执行权限:
1 | chmod +x clash-node.sh |
常用方式:
1 | ./clash-node.sh current |
八、交互式切换脚本:更适合日常使用
上面那个已经够用,但如果节点多、国旗多、名字长,手输还是不够舒服。
所以我又写了一个交互式版本:直接把节点全部编号列出来,输入数字即可切换。
保存为 clash-select.sh:
1 |
|
赋权并运行:
1 | chmod +x clash-select.sh |
九、什么时候该开启 TUN
flowchart TD
NeedGlobal["是否需要让普通命令自动走代理?"] -->|"否"| UseEnv["优先使用环境变量或显式 --proxy"]
NeedGlobal -->|"是"| NeedTun["是否需要更接近“系统全局接管”?"]
NeedTun -->|"否"| UseProxy["继续使用 HTTP/SOCKS + 环境变量/显式参数"]
NeedTun -->|"是"| EnableTun["启用 TUN(需要评估路由与 DNS 影响)"]
如果你只是在终端里:
- 安装工具
- 拉 GitHub 仓库
- 调 API
- 跑
curl - 用
pip、npm、apt
那其实很多时候:
HTTP/SOCKS 代理 + 环境变量 就够了。
但如果你希望的是:
- 普通命令也自动走代理
- 某些不读环境变量的程序也能走
- 更接近“系统全局代理”的效果
那就应该开启 TUN。
一个最小可用的 TUN 配置示例
1 | tun: |
改完后,一般需要用更高权限启动 Clash,例如:
1 | sudo ./clash -d . |
十、我对 TUN 的理解:它不是“必须”,而是“更彻底”
经过这次测试后,我对 TUN 的理解可以概括为:
- 只想让少数命令走代理:环境变量最轻量
- 想在终端里精确控制:HTTP/SOCKS +
curl --proxy最可控 - 想让系统级流量也尽量接管:再上 TUN
- 想长期维护舒服:建议把查询、切换、验证做成脚本
需要注意的不是“节点不通”,而是:
你以为自己在走代理,实际上根本没走。
日常工作流:我的命令清单
1. 开启当前 shell 代理
1 | export http_proxy=http://127.0.0.1:7890 |
2. 验证代理是否通
1 | curl -I https://www.google.com |
3. 查看当前节点
1 | ./clash-node.sh current |
4. 切到某个节点
1 | ./clash-node.sh switch "日本Z02" |
5. 交互式切换
1 | ./clash-select.sh |
6. 查看当前出口国家
1 | ./clash-node.sh country |
总结
这次在 Linux 上折腾 Clash,表面上看是“换节点、开代理、开 TUN”,本质上其实是把三件事想明白了:
- 代理端口 != 系统全局代理
- 节点可用 != 当前命令真的在走代理
- 脚本化比手敲命令重要得多
当你把这三件事理顺之后,很多原本不易定位的问题,通常可以拆解成更可执行的步骤:
- 先验证代理本身
- 再验证当前程序是否走代理
- 再验证出口国家
- 最后决定要不要上 TUN
如果你也在 Linux 服务器、远程开发、AI 工具、GitHub、安装脚本这类场景下使用 Clash,希望这篇文章能帮你把代理从“能用”升级到“好用”。




