最近为了让 Linux 主机能够更稳定地访问 GitHub 和部分外部服务,我重新整理了一套 Mihomo + pon / poff 的本机代理方案。
这套方案的重点不是“给全局网络开代理”,而是:只让 Linux 主机自己按需走代理,并且尽量不影响其他本地服务。
一、这篇文章要解决什么问题
我的目标比较明确:
- Mihomo 常驻运行
- 只监听本机回环地址
- 不对局域网其他设备开放代理
- 需要时一键打开当前 shell 代理
- 不需要时一键关闭代理
最终效果如下:
1 2 3 4
| 命令行程序(git / curl / apt 等) -> 127.0.0.1:7890 -> Mihomo -> 代理节点
|
也就是说,这套方案主要服务于:
而不会主动影响:
- 局域网其他设备
- 本机对内服务
- 不需要走代理的日常网络访问
二、准备条件
开始之前,需要具备这些前提:
- Linux 主机已经可以正常执行 Linux 命令
- 已经拿到一份可用的 Clash / Mihomo 配置
- 已经下载好 Mihomo 二进制,或者准备上传到服务器
我这里约定:
三、先清理旧代理残留
在正式配置之前,最好先把旧的代理环境变量和 Git 代理配置清掉。
在 Linux 主机执行:
1 2 3 4
| env | grep -i proxy git config --global --get http.proxy git config --global --get https.proxy grep -n 'proxy\|9999' ~/.bashrc ~/.profile ~/.zshrc 2>/dev/null
|
如果你之前残留过类似 127.0.0.1:9999 的旧代理配置,可以执行:
1 2 3
| unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY git config --global --unset http.proxy 2>/dev/null || true git config --global --unset https.proxy 2>/dev/null || true
|
如果 ~/.bashrc 里还写着旧代理变量,例如:
1 2
| export http_proxy=http://127.0.0.1:9999 export https_proxy=http://127.0.0.1:9999
|
建议一并删除或注释掉,然后重新加载:
四、安装 Mihomo 二进制
如果当前目录已经有 mihomo 二进制,可以直接安装:
1 2 3
| sudo mkdir -p /etc/mihomo sudo install -m 0755 ./mihomo /usr/local/bin/mihomo /usr/local/bin/mihomo -v
|
确认能输出版本信息即可。
五、编写 Mihomo 配置文件
1. 创建规则目录
1
| sudo mkdir -p /etc/mihomo/ruleset
|
2. 编辑主配置文件
1
| sudo nano /etc/mihomo/config.yaml
|
这里我保留了原本订阅的基本结构,同时做了几个关键调整:
allow-lan: false:只给本机使用,不开放局域网访问external-controller: 127.0.0.1:9091:避开常见的 9090 端口冲突dns.enable: false:避免绑定 53 端口导致权限问题
配置示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
| mixed-port: 7890 allow-lan: false mode: rule log-level: info
external-controller: 127.0.0.1:9091 secret: "请改成一个强密码"
dns: enable: false
proxies: - name: Example-US-Node type: vless server: node.YOUR_DOMAIN port: 443 uuid: 00000000-0000-0000-0000-000000000000 network: tcp udp: true tls: true flow: xtls-rprx-vision servername: YOUR_DOMAIN reality-opts: public-key: YOUR_PUBLIC_KEY_HERE short-id: YOUR_SHORT_ID client-fingerprint: chrome
proxy-groups: - name: PROXY type: select proxies: - Example-US-Node - DIRECT
rule-providers: reject: type: http behavior: domain path: ./ruleset/reject.yaml url: https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/reject.txt interval: 86400
direct: type: http behavior: domain path: ./ruleset/direct.yaml url: https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/direct.txt interval: 86400
proxy: type: http behavior: domain path: ./ruleset/proxy.yaml url: https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/proxy.txt interval: 86400
private: type: http behavior: domain path: ./ruleset/private.yaml url: https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/private.txt interval: 86400
apple: type: http behavior: domain path: ./ruleset/apple.yaml url: https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/apple.txt interval: 86400
icloud: type: http behavior: domain path: ./ruleset/icloud.yaml url: https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/icloud.txt interval: 86400
applications: type: http behavior: classical path: ./ruleset/applications.yaml url: https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/applications.txt interval: 86400
lancidr: type: http behavior: ipcidr path: ./ruleset/lancidr.yaml url: https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/lancidr.txt interval: 86400
cncidr: type: http behavior: ipcidr path: ./ruleset/cncidr.yaml url: https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/cncidr.txt interval: 86400
rules: - RULE-SET,reject,REJECT - RULE-SET,private,DIRECT - RULE-SET,applications,DIRECT - RULE-SET,icloud,DIRECT - RULE-SET,apple,DIRECT - RULE-SET,direct,DIRECT - RULE-SET,lancidr,DIRECT - RULE-SET,cncidr,DIRECT - RULE-SET,proxy,PROXY - MATCH,PROXY
|
六、先做本地测试
正式挂 systemd 之前,先做两步验证。
1. 测试配置文件是否合法
1
| sudo /usr/local/bin/mihomo -d /etc/mihomo -t
|
2. 前台启动验证代理是否可用
1
| sudo /usr/local/bin/mihomo -d /etc/mihomo
|
另开一个终端执行:
1 2
| curl -x http://127.0.0.1:7890 -I https://github.com curl -x http://127.0.0.1:7890 -I https://raw.githubusercontent.com
|
如果能返回 200、301、302 这一类响应,通常就说明代理已经正常工作。
测试完成后,用 Ctrl + C 结束前台进程。
七、配置 systemd 常驻运行
编辑服务文件:
1
| sudo nano /etc/systemd/system/mihomo.service
|
写入:
1 2 3 4 5 6 7 8 9 10 11 12 13
| [Unit] Description=mihomo Daemon After=network.target NetworkManager.service systemd-networkd.service iwd.service
[Service] Type=simple Restart=always ExecStartPre=/usr/bin/sleep 1s ExecStart=/usr/local/bin/mihomo -d /etc/mihomo ExecReload=/bin/kill -HUP $MAINPID
[Install] WantedBy=multi-user.target
|
加载并启动:
1 2 3 4 5
| sudo systemctl daemon-reload sudo systemctl enable mihomo sudo systemctl start mihomo sudo systemctl status mihomo --no-pager journalctl -u mihomo -n 50 --no-pager
|
再确认监听端口:
1
| ss -lntp | grep -E ':7890|:9091'
|
预期应看到:
127.0.0.1:7890127.0.0.1:9091
如果监听地址是 0.0.0.0,就说明配置没有达到“仅本机使用”的目标,需要重新检查。
八、配置 pon / poff
1. 为什么不用普通脚本
如果想让代理变量立即作用于当前 shell,会有一个常见坑:
- 普通脚本只能影响子进程
- 不能直接修改当前 shell 的环境变量
所以这里更稳妥的做法是:
- 写两个环境片段文件
- 再在
~/.bashrc 里定义 pon() / poff() 函数
2. 创建代理环境片段
1 2
| mkdir -p ~/.proxy nano ~/.proxy/pon.env
|
写入:
1 2 3 4 5 6 7
| export http_proxy=http://127.0.0.1:7890 export https_proxy=http://127.0.0.1:7890 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:7890 export ALL_PROXY=socks5://127.0.0.1:7890 echo "[proxy] ON -> 127.0.0.1:7890"
|
再创建关闭文件:
写入:
1 2
| unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY echo "[proxy] OFF"
|
3. 在 ~/.bashrc 中添加函数
编辑:
在文件末尾追加:
1 2 3 4 5 6 7 8 9 10 11
| pon() { source ~/.proxy/pon.env }
poff() { source ~/.proxy/poff.env }
ptest() { curl -x http://127.0.0.1:7890 -I https://github.com }
|
使配置立即生效:
九、如何使用
开启代理:
关闭代理:
测试代理:
查看当前环境变量:
我的使用习惯是:
- 平时默认
poff - 需要访问 GitHub、外部 API、模型服务时再
pon - 用完后再手动
poff
这样不会影响本机其他局域网服务。
十、Git 代理开关(可选)
如果还想单独控制 Git 的全局代理,也可以继续在 ~/.bashrc 中追加:
1 2 3 4 5 6 7 8 9 10 11
| gpon() { git config --global http.proxy http://127.0.0.1:7890 git config --global https.proxy http://127.0.0.1:7890 echo "[git proxy] ON" }
gpoff() { git config --global --unset http.proxy 2>/dev/null || true git config --global --unset https.proxy 2>/dev/null || true echo "[git proxy] OFF" }
|
重新加载:
以后就可以这样用:
1 2 3
| gpon git clone https://github.com/NousResearch/hermes-agent.git gpoff
|
十一、常见问题
1. 127.0.0.1:9090 被占用
如果默认控制端口冲突,可以改成:
1
| external-controller: 127.0.0.1:9091
|
2. listen udp :53: bind: permission denied
这通常是内置 DNS 尝试绑定 53 端口导致的,可以直接关闭:
3. cache.db: permission denied
如果用普通用户前台启动,Mihomo 可能没有权限往 /etc/mihomo 写缓存。
解决思路:
- 手工测试时使用
sudo - 正式运行交给
systemd
4. pon 执行了但环境变量没生效
这种情况基本就是把 pon 做成了普通脚本,而不是 shell function。
本篇文章使用 source ~/.proxy/pon.env 的方式,就是为了避免这个问题。
5. 规则文件下载失败
rule-providers 依赖从 GitHub 拉取规则,如果网络环境本身不通,第一次启动可能就会失败。
建议按下面顺序排查:
- 先确认代理节点可用
- 再用前台模式看日志
- 没问题后再切换到
systemd 常驻
十二、最终验证清单
按顺序执行下面这些命令,基本就能确认整套方案是否可用:
1 2 3
| sudo /usr/local/bin/mihomo -d /etc/mihomo -t sudo systemctl status mihomo --no-pager ss -lntp | grep -E ':7890|:9091'
|
然后继续验证 shell 代理:
1 2 3 4 5
| pon env | grep -i proxy ptest poff env | grep -i proxy
|
如果结果符合预期,就说明:
- Mihomo 已经常驻运行
- Linux 主机本机代理可用
pon / poff 开关正常
十三、总结
这套方案最大的优点,是把“代理服务常驻”和“当前 shell 是否走代理”拆开了。
也就是说:
- Mihomo 可以一直在后台运行
- 但 shell 默认不带代理环境变量
- 只有真正需要访问外网时才手动开启
这样既保留了灵活性,也尽量减少了对本机其他服务的干扰。
如果你的目标和我一样,是在 Linux 主机上做一个只给自己用、按需开启、尽量不影响内网服务的代理环境,那么这套方式会比较实用。