搭建 Mihomo 旁路代理的完整指南:分流代理,释放主路由性能

7 阅读5分钟

搭建 Mihomo 旁路代理的完整指南:分流代理,释放主路由性能

一、什么是旁路由透明代理?

“旁路由”并不是一个官方的网络术语,而是民间对一种常见网络方案的称呼。它指的是在主路由旁边,再设置一个专门处理复杂任务的设备。

在这个方案中,我们的# 搭建 Mihomo 旁路代理的完整指南:分流代理,释放主路由性能网络结构如下:

  • 主路由:作为家庭网络的“大门”,负责 Wi-Fi、DHCP 等基础功能。它的性能可能不强,我们不希望它承担过重的任务。
  • 旁路由:一台性能更强的、7x24 小时运行的 Linux 设备(例如 PVE 虚拟机/LXC 容器、树莓派、NUC 小主机等)。它在网络中只是一个普通设备,不作为网关。

我们的目标是:

  1. 所有设备的网络流量都先经过主路由
  2. 主路由对流量进行智能识别,判断哪些是需要代理的“国外流量”,哪些是“国内流量”。
  3. 主路由将“国外流量”转发旁路由处理。国内流量则直接放行。
  4. 旁路由上的 mihomo 核心接收到转发来的流量,执行代理,实现“科学上网”。

这样做的好处:

  • 释放主路由性能:主路由只做最简单的识别和转发,CPU 负荷极低,确保了家庭网络 Wi-Fi 的稳定和低延迟。
  • 发挥旁路由性能:复杂的代理规则、大量的连接数都由性能更强的旁路由承担,可以达到更高的代理速度。
  • 安全稳定:无需给主路由刷写可能不稳定的第三方固件,保证了核心网络设备的稳定性。

二、旁路由配置:运行 Mihomo 服务

首先,我们需要在旁路由(例如您的 LXC Ubuntu 容器)上配置好 mihomo

1. 准备 Mihomo

  • 下载并安装 mihomo 核心程序。仓库:github.com/metacubex/m…

  • 准备好您的配置文件(例如 config.yaml),确保其 tproxy-port 已经开启,并且 iptables: enable: true,这是实现透明代理的关键。

    # config.yaml 关键配置
    mixed-port: 7897
    tproxy-port: 9898 # 透明代理端口
    allow-lan: true
    iptables:
      enable: true # 必须开启,mihomo 会自动管理自己的 iptables 规则
      inbound-interface: eth0 # 旁路由的网卡名
    

2. 设置持久化服务 (Systemd)

为了让 mihomo 能开机自启并在异常时自动重启,我们为它创建一个 systemd 服务。

  • 在旁路由上创建文件 /etc/systemd/system/mihomo.service,内容如下(请根据您的实际路径修改 ExecStart):

    [Unit]
    Description=mihomo proxy service
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    Type=simple
    ExecStart=/usr/local/bin/mihomo -f /root/mihomo/config.yaml
    User=root
    Restart=on-failure
    RestartSec=5s
    # 在服务启动后,执行豁免规则脚本,解决端口转发冲突问题
    ExecStartPost=/usr/local/bin/apply_iptables_fixes.sh
    
    [Install]
    WantedBy=multi-user.target
    
  • 同时,创建 /usr/local/bin/apply_iptables_fixes.sh 脚本,用于解决 SSH 等端口转发的冲突问题(详见排错实践):

  • 最后,启用并启动服务:

    sudo chmod +x /usr/local/bin/apply_iptables_fixes.sh
    sudo systemctl daemon-reload
    sudo systemctl enable mihomo
    sudo systemctl start mihomo
    

三、主路由配置:智能识别与转发流量

这是整个方案的核心,主路由需要完成两件大事:识别流量、转发流量。

为了实现持久化并解决复杂的启动时序问题,我们采用 OpenWRT 系统中最可靠的 uci + 自定义脚本的方式。

1. 识别流量:使用 IPSet + iptables MARK

  • IPSet: 我们使用 ipset 来创建一个名为 china_ip 的集合,并将所有国内 IP 地址段放进去。相比于成千上万条 iptables 规则,ipset 的匹配效率极高。
  • iptables MARK: 我们在 mangle 表中设置规则,对流量进行“打标记”。逻辑是:“如果一个数据包的目标地址china_ip 集合里,就给它打上一个标记(例如 1)”。

2. 转发流量:使用策略路由 (Policy-Based Routing)

  • Linux 内核允许我们创建多张路由表。我们创建一个新的路由表(例如 100)。
  • 我们设置一条策略规则:ip rule add fwmark 1 table 100。意思是:“所有被打了标记 1 的数据包,都不要走默认的路由表,而是去查阅第 100 号路由表”。
  • 我们再在第 100 号路由表里只写一条规则:ip route add default via <旁路由IP> table 100。意思是:“所有查到这张表的数据包,你们的下一跳(网关)都是旁路由”。

3. 最终方案:创建持久化启动脚本

我们将所有命令整合到一个独立的启动脚本中,然后通过 uci 命令让它在防火墙启动时被调用。

第一步:创建 /data/my_proxy_script.sh 脚本

主路由上创建该文件,并写入以下健壮的脚本内容:

#!/bin/sh
(
  set -x
  echo "--- Starting custom route script at $(date) ---"
  
  # 1. 智能等待网络就绪
  echo "Waiting for 'br-lan' interface..."
  while ! ip a | grep -q 'br-lan'; do sleep 5; done
  echo "'br-lan' is up. Waiting 15s more..."
  sleep 15

  # 2. 配置 IPSet
  ipset create china_ip hash:net -exist
  wget -O /tmp/china_ip_list.new 'https://fastly.jsdelivr.net/gh/17mon/china_ip_list@master/china_ip_list.txt'
  if [ -s "/tmp/china_ip_list.new" ]; then
      ipset flush china_ip
      awk '!/^#|^$/{print "add china_ip " $0}' /tmp/china_ip_list.new | ipset restore
  fi
  rm -f /tmp/china_ip_list.new

  # 3. 配置策略路由
  ip rule add fwmark 1 table 100 2>/dev/null
  ip route flush table 100
  ip route add default via 192.168.31.2 dev br-lan table 100

  # 4. 配置 Mangle 表打标记
  iptables -t mangle -N PROXY_MARK 2>/dev/null
  iptables -t mangle -F PROXY_MARK
  iptables -t mangle -A PROXY_MARK -m set --match-set china_ip dst -j RETURN
  iptables -t mangle -A PROXY_MARK -s 192.168.31.2 -j RETURN
  iptables -t mangle -A PROXY_MARK -s 192.168.31.0/24 -j MARK --set-mark 1
  iptables -t mangle -C PREROUTING -s 192.168.31.0/24 -j PROXY_MARK 2>/dev/null || iptables -t mangle -A PREROUTING -s 192.168.31.0/24 -j PROXY_MARK

  # 5. 配置 Filter 表放行转发
  iptables -t filter -C FORWARD -m mark --mark 0x1 -j ACCEPT 2>/dev/null || iptables -t filter -I FORWARD 1 -m mark --mark 0x1 -j ACCEPT
  
  echo "--- Finished custom route script at $(date) ---"
) > /tmp/my_proxy_startup.log 2>&1 &

第二步:赋予脚本执行权限

chmod +x /data/my_proxy_script.sh

第三步:使用 uci 创建独立的防火墙启动项

# 清理一下,以防有旧的残留
uci delete firewall.MyProxy 2>/dev/null

# 创建新的防火墙 include 任务
uci set firewall.MyProxy=include
uci set firewall.MyProxy.type='script'
uci set firewall.MyProxy.path='/data/my_proxy_script.sh'
uci set firewall.MyProxy.enabled='1'

# 提交更改,使其永久生效
uci commit firewall

# 重启防火墙使配置生效
/etc/init.d/firewall restart

通过以上步骤,您就拥有了一个完全独立、持久化且能解决启动时序问题的透明代理方案。

四、常见问题与深度排错

在配置过程中,您可能会遇到各种意想不到的问题,例如规则不生效、端口转发冲突、HTTPS 证书错误、重启后规则丢失等。这些问题的根源往往与硬件加速、防火墙转发策略、脚本启动时序等底层机制有关。

我们已将一次完整的、从零开始的排错过程详细记录成文,其中包含了对这些常见问题的深入分析和最终解决方案。

详细内容请参考:[[旁路由透明代理与端口转发排错实战]]

通过以上步骤,您就可以搭建一套稳定、高效且不影响主路由性能的旁路由透明代理系统。