平台部署 预计阅读 15 分钟

OpenWrt 旁路由运行 mihomo 内核:透明代理部署要点

梳理主路由与旁路由的网关分工、mihomo 内核直跑的目录与服务配置、透明代理与 DNS 接管要点,以及断网回退的预案。

一、网络拓扑:先让一台终端经过旁路由

OpenWrt 旁路由部署 mihomo,包含三个独立环节:终端把流量交给旁路由,防火墙把连接送进内核,内核按规则选择出站。只启动 mihomo,或者只修改 DNS,都不等于完成透明代理。

本文采用单网口、同网段的 IPv4 测试拓扑,以 OpenWrt 23.05、24.10 系列常见的 firewall4 与 nftables 环境为基线。以下地址是完整示例,执行前应与实际网段逐项核对。已经运行 OpenClash、其他透明代理插件或自定义策略路由的设备,不应直接叠加这些规则。

设备地址或设置职责
主路由192.168.10.1/24宽带拨号、出口 NAT、继续提供 DHCP
OpenWrt 旁路由192.168.10.2/24运行 mihomo,接收测试终端流量
旁路由默认网关192.168.10.1供内核连接节点及直连上游
测试终端192.168.10.100/24网关与 DNS 均设为 192.168.10.2
旁路由 LAN 接口br-lan接收同一局域网内的测试流量

网关与 DHCP 的分工

  1. 在 OpenWrt 的“网络”→“接口”→“LAN”→“编辑”中设置静态地址、IPv4 网关和 DNS。确认旁路由自身能够访问网络。
  2. 在同一界面的“DHCP 服务器”→“常规设置”中勾选“忽略此接口”,避免主路由、旁路由同时发放地址。
  3. 先只修改测试终端的 IPv4 网关和 DNS。不要立即把主路由 DHCP 的网关选项改为旁路由地址。
  4. 检查“网络”→“防火墙”中的 LAN 区域策略。本文假定常见的 LAN 输入、输出和区域内转发均允许;受限网络需要另行设计放行规则。

同网段旁路由的直连响应可能由主路由直接返回终端,不一定再次经过旁路由。这种非对称路径会影响连接统计与状态防火墙判断。初次测试应保留主路由原有出口 NAT,不要为了“路径对称”直接在整个 LAN 上增加地址伪装。

二、内核目录:先验证二进制与最小配置

mihomo 是 Clash Meta 延续发展的代理内核,不是 OpenWrt 管理插件。直跑内核意味着配置目录、进程守护、订阅更新和防火墙规则均由管理员维护。应按 CPU 架构选择 Linux 二进制,不能仅凭设备商品名判断。

ubus call system board
uname -m
df -h /overlay
free -m

mkdir -p /etc/mihomo
chmod 700 /etc/mihomo
chmod 755 /usr/bin/mihomo
/usr/bin/mihomo -v

这些命令假定已把解压后的内核放到 /usr/bin/mihomo。例如 aarch64 通常对应 ARM64,但 ARMv7、MIPS 设备还需确认指令集、字节序和浮点 ABI。出现 Exec format error 时优先检查架构,而不是修改防火墙。版本号以本机 mihomo -v 输出为准,并保留这条输出用于后续排查。

配置文件:先用 DIRECT 验证接管链路

将以下内容保存为 /etc/mihomo/config.yaml。这是可测试的直连基线,没有配置代理节点,因此不会把流量送到代理服务器。先验证流量能够进入内核,再接入自己的节点和策略组,可以把网络问题与订阅问题分开。

mixed-port: 7890
tproxy-port: 7893
allow-lan: true
bind-address: 192.168.10.2
mode: rule
log-level: info
ipv6: false

dns:
  enable: true
  listen: 0.0.0.0:1053
  ipv6: false
  enhanced-mode: redir-host
  nameserver:
    - udp://223.5.5.5:53
    - udp://119.29.29.29:53

rules:
  - MATCH,DIRECT

7890 是 HTTP/SOCKS 混合代理入口,7893 是 TPROXY 入口,1053 是 mihomo DNS 监听端口。这里使用 redir-host,避免首次部署同时引入 Fake-IP 地址池与额外路由。两个上游 DNS 是示例中的直连解析器,并不等于加密 DNS。

chmod 600 /etc/mihomo/config.yaml
/usr/bin/mihomo -t -d /etc/mihomo -f /etc/mihomo/config.yaml

必须先通过配置测试,再启用流量接管。本文基线没有 GEOIP、GEOSITE 或规则集依赖;若换成订阅配置,还需检查相应数据文件、规则提供者下载地址以及策略组引用。面向桌面客户端生成的订阅,也可能带有不适合路由器的 DNS、TUN 或控制接口设置。

三、进程守护:用 procd 启动 mihomo

OpenWrt 使用 procd 管理服务。不要把长期进程直接挂在 SSH 会话里,也不要在计划任务中每分钟重复启动。下面的脚本负责启动、异常退出后重启及日志接入,不负责安装透明代理规则。

把以下内容保存为 /etc/init.d/mihomo:

#!/bin/sh /etc/rc.common

START=95
STOP=10
USE_PROCD=1

start_service() {
    /usr/bin/mihomo -t -d /etc/mihomo \
        -f /etc/mihomo/config.yaml || return 1

    procd_open_instance
    procd_set_param command /usr/bin/mihomo \
        -d /etc/mihomo -f /etc/mihomo/config.yaml
    procd_set_param respawn 3600 5 5
    procd_set_param stdout 1
    procd_set_param stderr 1
    procd_set_param file /etc/mihomo/config.yaml
    procd_close_instance
}
chmod 755 /etc/init.d/mihomo
/etc/init.d/mihomo enable
/etc/init.d/mihomo start
logread -e mihomo
ss -lnptu | grep -E ':(7890|7893|1053)\b'

若系统没有 ss,可用 netstat -lnptu 检查监听。日志出现端口占用时,应先查找旧代理进程、重复服务或 DNS 插件;不要随意换一个端口却忘记同步修改防火墙。

四、透明代理:TPROXY、策略路由与防火墙分别做什么

Linux 上的 TPROXY 可以接收 TCP 和 UDP,并保留原始目标地址。它需要三部分共同工作:nftables 选择连接,策略路由把带标记的数据包交给本机,mihomo 的透明监听接收连接。只有 tproxy-port 配置而没有前两项,终端流量不会自动进入内核。

以下示例只匹配 192.168.10.100,仅用于已确认没有冲突的测试环境。执行前运行 ip -4 rule show、ip -4 route show table 100 和 nft list ruleset,确认路由表 100、规则优先级 100 和标记位 0x1 未被其他服务使用。多 WAN、VPN 与其他代理经常已经占用这些资源。

内核模块与转发开关

使用对应固件软件源安装提供 nftables TPROXY 支持的模块;采用 opkg 的固件通常可检查 kmod-nft-tproxy。软件包与运行内核版本必须匹配。出现 Operation not supported 或找不到 TPROXY 表达式时,应先处理模块问题。

sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.conf.all.send_redirects=0
sysctl -w net.ipv4.conf.br-lan.send_redirects=0

ip -4 rule add priority 100 fwmark 0x1/0x1 lookup 100
ip -4 route add local 0.0.0.0/0 dev lo table 100

关闭发送 ICMP Redirect,可避免旁路由建议终端改走同网段主路由。不要忽略接口级设置。若设备启用了严格反向路径过滤,还需要检查 net.ipv4.conf.all.rp_filter 与 net.ipv4.conf.br-lan.rp_filter;策略路由环境中,严格模式可能丢弃合法数据包,应按网络安全要求调整为宽松模式或关闭。

只接管一个源地址的 nftables 规则

把以下内容保存为 /etc/mihomo/test-tproxy.nft。这是独立测试表,不应直接粘贴到 firewall4 的表内 include 文件中。首次加载前先检查语法,再实际安装;已有同名表时不要重复加载。

table inet mihomo_test {
    chain ingress_proxy {
        type filter hook prerouting priority mangle; policy accept;

        iifname != "br-lan" return
        ip saddr != 192.168.10.100 return

        meta l4proto { tcp, udp } th dport 53 return

        ip daddr {
            0.0.0.0/8,
            10.0.0.0/8,
            100.64.0.0/10,
            127.0.0.0/8,
            169.254.0.0/16,
            172.16.0.0/12,
            192.168.0.0/16,
            224.0.0.0/4,
            240.0.0.0/4
        } return

        meta l4proto { tcp, udp } counter \
            tproxy to :7893 meta mark set 0x1 accept
    }

    chain ingress_dns {
        type nat hook prerouting priority dstnat; policy accept;

        iifname "br-lan" ip saddr 192.168.10.100 \
            meta l4proto { tcp, udp } th dport 53 \
            counter redirect to :1053
    }
}
nft -c -f /etc/mihomo/test-tproxy.nft
nft -f /etc/mihomo/test-tproxy.nft
nft list table inet mihomo_test

DNS 的 53 端口先从透明代理链返回,再由后面的 NAT 链重定向到 1053,避免普通 DNS 请求先被 TPROXY 接走。私有地址和组播地址直接放行,便于保留路由器管理、局域网设备访问等基本功能;如果组织内部还有公网地址段或专用路由,也应纳入排除范围。

nftables 测试链中的 accept 不会跳过 firewall4 后续的其他基础链。TPROXY 数据包保留原始目标端口,不能仅放行“目标端口 7893”来替代输入策略。本文使用 LAN 输入允许的测试环境;采用 LAN 输入拒绝策略时,需要在 firewall4 中为 LAN 来源、相应标记的 TCP/UDP 数据包建立受限输入放行规则,并单独允许 DNS 1053。

五、DNS 接管:区分传统解析、加密 DNS 与解析回环

终端网关和 DNS 都指向旁路由,并不意味着所有域名解析都会进入 mihomo。上述规则接管的是经过旁路由的 TCP/UDP 53 请求;浏览器的安全 DNS、系统的 Private DNS,以及应用内置 DoH,可能通过 443 或 853 端口访问其他解析器。

  • 基础测试:暂时关闭测试终端的加密 DNS,明确检查传统 DNS 链路,再恢复相关功能验证策略。
  • 端口分工:保留 OpenWrt dnsmasq 的 53 端口,mihomo 使用 1053。不要让两个进程争抢同一个监听地址和端口。
  • 上游回环:不要让 mihomo 的上游指向 dnsmasq,同时又把 dnsmasq 的上游指回 mihomo。这会造成解析循环或超时。
  • 节点域名:增加代理节点后,检查节点服务器域名的解析路径。使用 proxy-server-nameserver 可单独指定节点域名解析器,避免建立代理连接前还依赖该代理。
  • 局域网域名:需要解析 DHCP 主机名时,应为内部域配置专门的解析策略,并确认没有形成上述回环。

示例只按测试终端源地址接管 DNS,因此旁路由自己发出的 DNS 不会被同一规则再次截获。若后续把规则扩大到所有源地址,必须重新审查内核上游、节点连接与设备本机流量的豁免条件,不能简单删除源地址限制。

TUN 模式为什么不是额外再开一个开关

mihomo 也支持 TUN,但 TUN 需要相应的内核设备支持、路由与 DNS 接管设计。auto-route、auto-redirect 等设置可能改变现有路由和 nftables 规则,不能与本文的手工 TPROXY 方案直接叠加。单网口旁路由还要验证转发流量是否真正进入 TUN,而不是只验证路由器本机请求。

如果选用 TUN,应先撤销本文的测试表和策略路由,再按当前 mihomo 版本的 TUN 配置重新部署。两种方式的目标相同,都是把需要处理的连接送入内核;排查时保持一条明确的接管路径,比同时启用多个入口更容易定位问题。

六、验收顺序:从直连基线到代理策略

先确认旁路由自身可联网,再验证终端流量。示例基线的最终规则是 MATCH,DIRECT,出口 IP 与普通直连一致是正常现象,不能据此认定没有接管。应结合计数器和内核日志判断。

  1. 配置检查:运行 mihomo -t,确认没有 YAML 缩进错误、未知策略组或规则提供者加载失败。
  2. 显式代理检查:在测试终端执行下方 curl 命令。该步骤只验证 7890 入口,不验证透明接管。
  3. DNS 检查:向 192.168.10.2 查询域名,观察 DNS NAT 计数器是否增长。NAT 链计数反映新连接匹配,不等于每个 DNS 数据包的数量。
  4. 透明连接检查:关闭终端上的显式代理,再访问公开网站,检查 TPROXY 计数器及 logread -e mihomo 中的连接记录。
  5. 代理出站检查:导入有效节点,配置真实策略组并替换最终规则后,重复请求。确认日志中的出站名称与预期一致,再测试大文件、视频和 UDP 应用。
# 在测试终端执行
curl -I --proxy http://192.168.10.2:7890 https://example.com/
nslookup example.com 192.168.10.2
curl -I --noproxy '*' https://example.com/

# 在旁路由执行
ip -4 rule show
ip -4 route show table 100
nft list table inet mihomo_test
logread -e mihomo

浏览器正常而游戏异常,常见原因包括 UDP 接管缺失、节点不支持 UDP、应用使用不同地址族。小网页正常但大连接停顿,则应继续检查 MTU、路径 MTU 发现和链路丢包。不要直接把这些问题都归为 DNS 故障,也不要在缺少日志时随意调整内核参数。

测试期间可在“网络”→“防火墙”中暂时关闭软件、硬件流量卸载,减少快速路径对观察结果的干扰。确认方案稳定后,再逐项恢复并复测。本文没有提供实测吞吐数字:设备 CPU、节点协议、加密算法和出口带宽都会影响结果,应以本机相同条件下的重复测试为准。

七、断网回退:先恢复网关,再撤销接管规则

把全网 DHCP 网关改为旁路由后,旁路由断电不会让客户端自动改回主路由。procd 能处理进程异常退出,但不能修复硬件掉电、错误规则或上游失联。因此回退方案应在扩大部署范围之前准备好。

单终端测试的恢复步骤

  1. 把测试终端的 IPv4 网关和 DNS 改回 192.168.10.1,或恢复由主路由 DHCP 自动获取。
  2. 在旁路由删除测试 nftables 表,停止继续拦截连接。
  3. 仅删除本次创建的策略路由和本地路由,然后停止内核。
  4. 重新建立网络连接或清理终端 DNS 缓存,再确认直连恢复。已经建立的代理连接通常需要重新连接。
nft delete table inet mihomo_test
ip -4 rule del priority 100 fwmark 0x1/0x1 lookup 100
ip -4 route del local 0.0.0.0/0 dev lo table 100
/etc/init.d/mihomo stop
/etc/init.d/mihomo disable

只在确认这些对象由本文实验创建时执行删除命令。不要使用 nft flush ruleset 清空整机规则,也不要清空整张策略路由表,这会影响 firewall4、VPN 和其他网络服务。

扩大到全网前的维护清单

  • 保存主路由原有 DHCP 网关、DNS 设置,并记录租约更新时间;恢复选项后,旧租约终端仍可能继续使用旁路由。
  • 保留不依赖旁路由的管理入口,例如固定地址的维护电脑,以及主路由的管理地址。
  • 订阅更新采用“下载到临时文件 → 配置测试 → 替换 → 重启”的顺序,失败时保留上一份可用配置。
  • 检查磁盘空间和日志量,避免长期开启 debug 把有限的闪存空间耗尽。
  • 实际演练一次内核停止和旁路由断电,验证客户端恢复步骤,而不是只测试正常启动。

稳定部署的判断标准不是服务显示“运行中”,而是网关、DNS、透明接管、规则出站和故障回退都能分别验证。先用一台终端完成闭环,再逐步扩大范围,可以明显缩小每次变更的影响面。

下载Clash