mihomo + proxychains4 Linux 服务器代理速查

适用场景:Linux 服务器无 GUI,持有机场订阅链接,需要在终端按需使用代理。核心思路:mihomo 负责节点管理与连接,proxychains4 负责让任意命令走代理。


目录


1. 安装

1.1 检测 CPU 指令集(选版本)

grep -m1 flags /proc/cpuinfo | tr ' ' '\n' | grep -E 'avx2|sse4_2'
输出选择版本
avx2v3
只有 sse4_2v2
都没有v1(保底)

1.2 下载并安装

前往 mihomo Releases,Ubuntu/Debian 选 .deb 包:

mihomo-linux-amd64-v3-v1.x.x.deb
dpkg -i mihomo-linux-amd64-v3-v1.x.x.deb

装完后 mihomo 自动注册为 systemd 服务,工作目录为 /etc/mihomo/


2. 订阅配置

2.1 拉取订阅

机场通用订阅 URL 根据 User-Agent 返回不同格式,指定 clash-meta 获取 Clash YAML:

# 先备份默认配置
mv /etc/mihomo/config.yaml /etc/mihomo/config.yaml.bak
 
# 拉取订阅
curl -A "clash-meta" "你的订阅URL" -o /etc/mihomo/config.yaml

验证格式(开头应为 mixed-port: 等 YAML 字段):

head -30 /etc/mihomo/config.yaml

2.2 下载 MMDB(首次启动前必做)

机场订阅的 config 含 GEOIP,CN,DIRECT 等规则,mihomo 启动时会解析全部规则,无论当前是什么模式。解析到 GEOIP 规则时会尝试下载 MMDB 数据库,而服务器没有代理访问不了 GitHub,导致启动失败循环。

必须在首次启动前手动下载 MMDB,且下载时服务不能在运行(运行中 mihomo 会把不完整的文件判定为无效并自动删除):

# 确认服务未运行
systemctl stop mihomo
 
# 通过 GitHub 代理下载
curl -L "https://gh-proxy.org/https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb" \
  -o /etc/mihomo/geoip.metadb
 
# 确认文件存在且大小正常(约 8MB)
ls -lh /etc/mihomo/geoip.metadb

2.3 代理模式

mihomo 有三种工作模式,由 config 顶部 mode 字段控制,也可通过 REST API 运行时切换:

模式配置值行为
规则模式rulerules 逐条匹配,命中哪条走哪条(订阅默认)
全局模式global所有流量走代理,规则不参与路由
直连模式direct所有流量直连,不走代理
# 运行时切换模式(无需重启)
curl -s -X PUT http://127.0.0.1:9090/configs \
  -H "Content-Type: application/json" \
  -d '{"mode":"global"}'

3. 服务管理

# 启动并设为开机自启
systemctl enable --now mihomo
 
# 查看状态
systemctl status mihomo
 
# 实时查看日志
journalctl -u mihomo -f
 
# 重启(修改配置后)
systemctl restart mihomo
 
# 验证端口已监听(默认 7890)
ss -tlnp | grep 7890

4. 节点管理(REST API)

mihomo 提供 REST API,默认监听 127.0.0.1:9090(由 config 中 external-controller 字段控制)。

安装 jq 处理 JSON 输出:

apt install jq

4.0 查询主代理组名

curl -s http://127.0.0.1:9090/group | jq -r '.proxies[] | select(.type == "Selector" and .name != "GLOBAL") | .name' | head -1
一分机场

脚本中用 GROUP=$(...) 自动取值,无需手动填写。

4.1 查看当前选中节点

GROUP=$(curl -s http://127.0.0.1:9090/group | jq -r '.proxies[] | select(.type == "Selector" and .name != "GLOBAL") | .name' | head -1)
curl -s http://127.0.0.1:9090/proxies/${GROUP} | jq '.now'
"自动选择"

4.2 列出代理组内所有节点

GROUP=$(curl -s http://127.0.0.1:9090/group | jq -r '.proxies[] | select(.type == "Selector" and .name != "GLOBAL") | .name' | head -1)
curl -s http://127.0.0.1:9090/proxies/${GROUP} | jq -r '.all[]'
自动选择
故障转移
🇯🇵日本专线-0.1倍率
🇯🇵日本专线2-0.1倍率
...

4.3 测速并切换节点

写入脚本文件,之后直接用命令名调用,无历史折行问题,可分享给他人:

cat > /usr/local/bin/proxy-switch << 'EOF'
#!/bin/bash
TMPDIR=$(mktemp -d)
GROUP=$(curl -s http://127.0.0.1:9090/group | jq -r '.proxies[] | select(.type == "Selector" and .name != "GLOBAL") | .name' | head -1)
echo "当前组: ${GROUP},测试真连接延迟中"
curl -s http://127.0.0.1:9090/proxies/${GROUP} | jq -r '.all[]' > "$TMPDIR/nodes"
 
i=1
while IFS= read -r node; do
  {
    encoded=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.stdin.read().strip()))" <<< "$node")
    result=$(curl -s -G "http://127.0.0.1:9090/proxies/${encoded}/delay" \
      --data-urlencode "url=http://www.gstatic.com/generate_204" \
      -d "timeout=3000")
    delay=$(echo "$result" | jq -r '.delay // "超时"')
    printf "%3d  %-8s  %s\n" "$i" "${delay}ms" "$node"
  } > "$TMPDIR/result_$(printf '%04d' $i)" &
  ((i++))
done < "$TMPDIR/nodes"
wait
 
cat "$TMPDIR"/result_*
 
CURRENT=$(curl -s http://127.0.0.1:9090/proxies/${GROUP} | jq -r '.now')
CURRENT_NUM=$(grep -Fn "$CURRENT" "$TMPDIR/nodes" | head -1 | cut -d: -f1)
CURRENT_DELAY=$(awk '{print $2}' "$TMPDIR/result_$(printf '%04d' $CURRENT_NUM)")
 
read -ep "当前节点:${CURRENT},延迟:${CURRENT_DELAY},是否切换?[Y/n]: " ANSWER
if [[ "$ANSWER" =~ ^[Yy]$ ]]; then
  read -ep "输入节点编号: " NUM
  NODE=$(sed -n "${NUM}p" "$TMPDIR/nodes")
  SELECTED_DELAY=$(awk '{print $2}' "$TMPDIR/result_$(printf '%04d' $NUM)")
  echo "已选节点:${NODE},延迟:${SELECTED_DELAY}"
  curl -s -X PUT http://127.0.0.1:9090/proxies/${GROUP} \
    -H "Content-Type: application/json" \
    -d "{\"name\":\"$NODE\"}"
  echo "切换完成"
fi
 
rm -rf "$TMPDIR"
EOF
 
chmod +x /usr/local/bin/proxy-switch

之后每次直接运行:

proxy-switch
当前组: 一分机场,测试真连接延迟中
  1  194ms     自动选择
  2  256ms     故障转移
  3  超时ms    🇯🇵日本专线-0.1倍率
  4  47ms      🇯🇵日本专线2-0.1倍率
 15  70ms      🇸🇬新加坡专线
 21  287ms     🇳🇱荷兰专线
 40  超时ms    🇭🇰香港-移动专属1号
...

当前节点:自动选择,延迟:194ms,是否切换?[Y/n]: Y
输入节点编号: 4
已选节点:🇯🇵日本专线2-0.1倍率,延迟:47ms
切换完成

节点名含 emoji 或中文不要手动输入,终端/SSH 层会把 emoji 编码损坏。用编号从 API 输出取名,字节序列才保证正确。

切回自动测速模式(单独使用时):

curl -s -X PUT http://127.0.0.1:9090/proxies/$(curl -s http://127.0.0.1:9090/group | jq -r '.proxies[] | select(.type == "Selector" and .name != "GLOBAL") | .name' | head -1) \
  -H "Content-Type: application/json" \
  -d '{"name":"自动选择"}'

5. proxychains4

5.1 配置文件

编辑 /etc/proxychains4.conf,关键项:

dynamic_chain          # 链中某个代理不可用时自动跳过
proxy_dns              # DNS 也走代理
[ProxyList]
socks5  127.0.0.1  7890    # 注意:必须用 IP,不能写 localhost

dynamic_chain 模式下非首个代理不允许使用主机名,必须写 127.0.0.1

5.2 使用方式

# 在任意命令前加前缀
proxychains4 curl https://ipinfo.io
proxychains4 wget https://example.com/file.tar.gz
proxychains4 git clone https://github.com/xxx/xxx

验证出口 IP:

proxychains4 curl ip.fm

6. 排查

现象原因解决
端口未监听,服务反复重启config 有 GEOIP 规则,MMDB 不存在见 2.2:停服务 → 下载 MMDB → 启动
proxy localhost has invalid valueproxychains4 不允许非首个代理用主机名localhost 改为 127.0.0.1
MMDB 文件下载后消失mihomo 运行中检测到不完整文件自动删除systemctl stop mihomo 再下载
节点切换无效节点名与 config 不完全一致jq -r '.all[]' 复制精确名称
启动正常但代理不通OKZTWO 组当前选中的是无效节点切换到 自动选择 或手动测延迟后选择