OpenWrt 旁路由跑 mihomo 内核:透明代理部署流程概览

梳理在 OpenWrt 主路由或旁路由上直接运行 mihomo 内核的整体流程,包括内核放置、配置目录、透明代理转发与局域网设备网关设置。

先确定部署边界:内核、网关与透明代理是三件事

在 OpenWrt 上直接运行 mihomo,不等于安装了一个带界面的 Clash 客户端。内核负责读取配置、建立代理连接和执行规则;系统负责把终端流量送进内核。启动日志正常,只能证明进程已经运行,不能证明局域网设备正在使用代理。

本文以 OpenWrt 23.05、24.10 常见的 firewall4 与 nftables 环境为背景,采用 Linux TUN 加自动路由的部署思路。具体字段是否可用,以实际 mihomo 版本的配置检查结果为准。旧版 firewall3、厂商定制防火墙和已有代理插件,不应直接套用同一套接管规则。

  • 主路由部署:OpenWrt 本来就是终端默认网关,重点是内核接管、防火墙放行与 DNS 转发。
  • 旁路由部署:OpenWrt 与主路由处于同一局域网,还需要调整测试终端的网关与 DNS。
  • 显式代理测试:应用主动连接 7890 混合端口,只用于先验证节点与规则,不代表透明代理已经完成。

规划旁路由地址与终端网关

先用一台终端验证,不要立即修改整个局域网的 DHCP 下发参数。下面的地址是一套完整示例;实际部署时,应按现有子网统一调整,不能只改其中一个地址。

设备或参数示例值用途
局域网网段192.168.10.0/24主路由、旁路由与终端处于同一子网
主路由192.168.10.1连接互联网,继续提供 DHCP
OpenWrt 旁路由192.168.10.2静态地址,避免与 DHCP 地址池冲突
旁路由默认网关192.168.10.1内核连接节点及直连目的地的上游
测试终端192.168.10.100保留原有子网掩码
终端网关与 DNS192.168.10.2将测试终端流量与解析请求交给旁路由

LuCI 中先检查「网络」→「接口」→「LAN」→「编辑」的静态地址、IPv4 网关和 DNS 设置。单网口旁路由通常通过 br-lan 访问主路由;双网口主路由则可能通过 PPPoE 或其他 WAN 设备出站,不能根据网卡名称猜出口。

ip -4 addr show
ip -4 route show
ip route get 223.5.5.5
cat /etc/resolv.conf

旁路由自身的默认路由应指向主路由,而不是指向自身。初次部署时,旁路由系统 DNS 先使用可直接访问的解析服务,避免出现“内核启动需要解析节点域名,但解析又依赖尚未启动的内核”的循环。

主路由保留唯一的 DHCP 服务即可。旁路由不要再向同一广播域发放另一套地址。IPv6 也必须单独规划:即使手工改了终端 IPv4 网关,终端仍可能通过主路由的 IPv6 路由通告直接出站。

放置 mihomo 内核与配置目录

确认架构、内核模块和存储空间

先检查 CPU 架构与固件信息,再选择对应的 Linux 二进制。x86_64、aarch64 与不同 MIPS 变体不能混用;部分发布包还区分指令集等级。文件名看起来相近,不代表能够在同一设备上执行。

uname -m
ubus call system board
df -h /overlay /tmp
opkg list-installed | grep -E 'kmod-tun|firewall4|nftables'

在使用 opkg 的官方固件上,可通过 opkg update 与 opkg install kmod-tun 安装 TUN 模块。模块必须与当前固件内核匹配;遇到依赖不匹配时,应修复固件与软件源对应关系,不要强制安装其他内核版本的模块。自动接管所需的 nftables 功能也取决于固件编译选项。

固定程序路径与工作目录

将已解压且架构匹配的内核上传至 /usr/bin/mihomo,配置放入 /etc/mihomo/config.yaml。配置可能包含订阅凭据,目录与文件不应对普通用户开放。设备的持久空间不足时,应先规划外部存储,而不是把正式配置长期放在重启会清空的 /tmp。

mkdir -p /etc/mihomo
chmod 700 /etc/mihomo
chmod 755 /usr/bin/mihomo
chmod 600 /etc/mihomo/config.yaml
/usr/bin/mihomo -v
/usr/bin/mihomo -t -d /etc/mihomo -f /etc/mihomo/config.yaml

-d 指定工作目录,-f 指定配置文件,-t 只检查配置。若配置引用 GeoIP、GeoSite、规则集或代理提供者文件,还需检查相应路径、读取权限和更新网络。首次排障可以先去掉这些外部依赖,避免把下载失败误判成 TUN 故障。

先验证显式代理,再启用 TUN 接管

推荐分两次启动。第一次使用实际可用的节点配置,将 tun.enable 设为 false,在路由器本机通过混合端口测试连接。第二次确认节点可用后,再开启 TUN 与自动路由。这样可以把节点问题和转发问题分开。

下面展示一个最小结构,用于检查配置与直连基线。它没有代理节点,策略组也只有 DIRECT,因此不会产生代理出口。正式使用时,应合并订阅中的有效节点或 proxy-providers,并将实际节点加入策略组;不要直接覆盖已有完整配置。

mixed-port: 7890
allow-lan: false
bind-address: 127.0.0.1
mode: rule
log-level: info
ipv6: false

tun:
  enable: false
  device: mihomo
  stack: mixed
  auto-route: true
  auto-redirect: true
  auto-detect-interface: true
  dns-hijack:
    - any:53

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  default-nameserver:
    - 223.5.5.5
  nameserver:
    - 223.5.5.5
    - 119.29.29.29

proxies: []

proxy-groups:
  - name: 出口选择
    type: select
    proxies:
      - DIRECT

rules:
  - IP-CIDR,192.168.10.0/24,DIRECT,no-resolve
  - IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
  - MATCH,出口选择

先在前台运行 /usr/bin/mihomo -d /etc/mihomo -f /etc/mihomo/config.yaml,通过另一条 SSH 会话观察端口。如果固件已安装 curl,可执行下列请求;该命令只检验路由器本机到混合端口的链路,不检验局域网透明转发。

curl --proxy http://127.0.0.1:7890 --connect-timeout 10 --max-time 20 -I https://example.com/

导入真实节点后,确认「出口选择」不再停留在 DIRECT,并结合日志中的匹配规则、策略组和节点名称判断请求路径。单看网页是否打开,无法区分直连成功与代理成功。

打通 TUN、策略路由与 OpenWrt 防火墙

显式代理通过后,将 tun.enable 改为 true,重新检查配置并启动。auto-route 负责建立接管所需路由,Linux 下的 auto-redirect 使用 nftables 等机制协助流量重定向。自动生成的路由表编号、规则优先级和链名可能随版本变化,不应把网上某一组固定编号当作通用标准。

ip link show mihomo
ip rule show
ip route show table all
nft list ruleset
sysctl net.ipv4.ip_forward

确认三类系统条件

  1. TUN 设备存在:应能看到配置中指定的 mihomo 设备。若缺失,先检查 /dev/net/tun、模块和启动权限。
  2. 路由接管生效:对比启停前后的 ip rule、路由表和 nftables 规则。内核日志不应持续出现创建接口或添加规则失败。
  3. 转发未被防火墙阻断:IPv4 转发应启用,LAN 到 TUN 的转发路径也要被允许。只看到 TUN 接口,并不能证明 firewall4 已经允许转发。

在 LuCI「网络」→「防火墙」→「常规设置」检查区域与转发。采用独立 TUN 区域时,可按实际界面将设备 mihomo 关联到该区域,并允许 LAN 到该区域的转发;区域的入站权限与转发权限是两回事。不要为了测试直接把 WAN 入站改为接受。

不同固件对非托管设备的区域绑定方式、自动重定向与 firewall4 的衔接存在差异。因此,这一步必须结合当前规则集判断,不宜复制一份固定的 iptables 脚本。尤其不要同时追加 REDIRECT、TPROXY 和自动 TUN 三套接管规则;本文流程采用的是 TUN 路线。

单臂旁路由还要观察同接口转发、回程路径与连接跟踪。部分直连流量可能从 br-lan 进入后又从同一接口发给主路由。如果出现只通单向、连接间歇中断,应抓包确认源地址和回包路径,再决定是否需要针对性源地址转换;不要先对整个 LAN 盲目开启伪装。

首次排障建议在「网络」→「防火墙」中暂时关闭软件流量分载与硬件流量分载。待链路稳定后再逐项恢复并复测。旁路由可以上网而终端不能上网时,优先检查转发路径,不要先更换节点。

安排 DNS 转发,避免解析回环与 IPv6 旁路

示例中的 DNS 链路是:终端访问旁路由 53 端口,由 dnsmasq 转发到本机 mihomo 的 1053 端口,再访问上游解析器。端口分开后,dnsmasq 与 mihomo 不会争抢同一个监听地址。

在 LuCI「网络」→「DHCP/DNS」→「常规设置」中,将 DNS 转发目标设为 127.0.0.1#1053;在对应的高级设置中检查“不使用上游提供的解析服务器”选项。界面标签会随 LuCI 版本变化,关键是让 dnsmasq 不再把请求同时交给其他自动获得的上游。

# 先备份,以下操作针对第一个 dnsmasq 实例
cp /etc/config/dhcp /etc/config/dhcp.before-mihomo
uci set dhcp.@dnsmasq[0].noresolv='1'
uci -q delete dhcp.@dnsmasq[0].server
uci add_list dhcp.@dnsmasq[0].server='127.0.0.1#1053'
uci commit dhcp
/etc/init.d/dnsmasq restart

nslookup example.com 127.0.0.1

这组命令会替换该实例已有的 DNS 转发列表。若原来配置了企业内网域名的条件转发,应先记录并保留相应条目;多 dnsmasq 实例也不能直接假定第一个就是 LAN 使用的实例。终端还需确认其 DNS 地址确实是 192.168.10.2。

区分普通 DNS、fake-ip 与加密 DNS

  • fake-ip:使用此模式时,查询可能返回 198.18.0.0/16 中的地址。这是虚拟映射,不是目标网站的真实公网地址;对应连接必须继续由内核接管。
  • 普通 DNS 劫持:any:53 用于接管相应的普通 DNS 请求,不代表能识别并重定向所有解析协议。
  • DoH 与 DoT:浏览器安全 DNS、应用内 DoH、TCP 853 的 DoT 不会因为配置了普通 53 端口劫持就自动服从 dnsmasq。测试时应先确认应用解析路径。
  • 上游选择:示例使用普通 IP 上游是为了缩短启动依赖链,并未启用加密解析。改用带域名的 DoH 地址时,应另行规划引导解析与节点域名解析。

ipv6: false 只限制内核相应行为,不会关闭终端收到的 IPv6 默认路由。初次验证可以暂时关闭测试终端 IPv6,随后再规划 IPv6 TUN、路由通告和防火墙。不要用“IPv4 出口正确”推断双栈流量都已接管。

通过 procd 管理启动与重启

确认前台运行、DNS 与终端访问都正常后,再注册开机服务。下面的 procd 脚本只负责守护进程,不包含订阅更新或自定义防火墙逻辑。保存为 /etc/init.d/mihomo,不要同时保留另一个插件的同名服务。

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

START=99
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

启动服务前,先结束原先前台运行的内核,避免两个实例争抢端口与 TUN 设备。此脚本默认以 root 运行,因为创建 TUN、配置路由与防火墙需要相应权限;这也意味着配置文件、订阅来源和内核文件都需要严格控制。

修改配置后,先运行 mihomo -t 再执行 /etc/init.d/mihomo restart。脚本中的文件声明不等于自动订阅更新器;更新订阅仍需独立安排下载、配置检查与原子替换。配置包含凭据时,也不要将完整启动日志直接发布到公开渠道。

开机顺序较晚不等于网络已经可用。必须做一次整机重启测试,观察接口上线后是否能解析节点域名、建立连接并恢复终端访问。依赖远程规则集的部署,还要考虑冷启动时外部文件暂时不可达的情况。

按链路验收,并保留回退路径

验收应从路由器本机推进到单台终端,最后才扩展到 DHCP 下发。每次只改变一个变量,记录对应日志与网关设置。测速结果只能说明当时的传输表现,不能替代路由和 DNS 路径检查。

现象优先检查判断依据
内核无法启动架构、配置、端口、TUN 模块查看配置检查与启动错误,不先改终端网关
显式代理正常,终端失败终端网关、TUN 接管、LAN 转发比较终端请求是否进入内核日志
IP 可达,域名访问失败dnsmasq、1053 监听、上游解析分别测试旁路由和终端的 DNS 请求
部分应用仍然直连规则、IPv6、应用内 DNS核对实际匹配策略与双栈出口
防火墙重载后中断自动生成规则是否仍存在对比重载前后 nftables 与策略路由
重启后无法恢复服务启用状态、接口时序、冷启动依赖从系统日志定位第一处失败

单终端通过后再扩展部署

  1. 终端先访问主路由和旁路由管理地址,确认局域网直连正常。
  2. 检查终端 IPv4 默认网关与 DNS 均指向旁路由,清理旧 DNS 缓存,再建立新的浏览器连接。
  3. 分别验证应当直连与应当代理的请求,查看对应规则和节点,不只观察页面加载结果。
  4. 确认 UDP 应用、IPv6 策略及防火墙重载后的表现,再调整主 DHCP 服务的网关和 DNS 下发值。

正常停止后,检查 TUN 接口、策略路由和自动生成的防火墙规则是否已清理。若仍有残留,依据保存的基线恢复;不要远程执行清空整个 nftables 规则集的命令。需要清理运行状态时,可在恢复持久配置后安排重启。

OpenWrt 旁路由部署的核心不是把二进制放到路由器上,而是把终端网关、DNS、流量接管、规则出口和服务生命周期接成一条可验证的链路。按这个顺序完成检查,后续更换订阅、调整分流或升级内核时,才能明确问题发生在哪一层。

下载Clash 安装包与系统要求