本文思路基本遵循 iKuai与Openwrt的有机结合:传统旁路由方案的完美替代,主要差异点如下:
- 虚拟化平台: unRaid 替换为 Proxmox VE (PVE)
- 透明网关: OpenWRT 替换为 Debian + Mihomo
- DNS 服务: paopaodns 替换为 SmartDNS + AdGuard Home 组合
网络拓扑
为方便描述,下文统一将处理出站流量的虚拟机称为透明网关 (gateway)。
架构核心思想
本方案采用“主路由 + 透明网关”的模式。iKuai 作为主路由,以其出色的稳定性、多线负载和流控能力负责整体网络的 DHCP、NAT 和流量调度。透明网关则是一个专职处理特定流量(如国际流量)的“处理器”。iKuai 通过策略路由(PBR)将特定流量“扔”给透明网关处理,处理完毕后再由透明网关“扔”回给 iKuai,由 iKuai 统一出口。这种架构实现了功能解耦,稳定性和灵活性兼得。
iKuai (主路由):
- WAN1: 用于 PPPoE 拨号或从光猫 DHCP 连接到外网。
- 物理网卡:
eth3
(硬件直通)
- 物理网卡:
- LAN: 地址为
192.168.100.1
,桥接所有局域网内的网卡,构成统一的二层网络。eth1
,eth2
: 硬件直通,连接 AP 或其他有线设备。vmbr0
: PVE 虚拟网桥,专用于 PVE 的 Web 管理界面访问,桥接到 LAN 使其可从内网访问。vmbr2
: PVE 虚拟网桥,作为通用网桥,接入其他虚拟机或容器。
- WAN2: 逻辑接口,作为 iKuai 与透明网关之间的数据通道。
- IP 地址:
192.168.200.2
- 网关指向:
192.168.200.1
(透明网关的 LAN 地址) - 网卡:
vmbr1
(PVE 虚拟网桥)
- IP 地址:
- WAN1: 用于 PPPoE 拨号或从光猫 DHCP 连接到外网。
gateway (透明网关):
- LAN: 接收来自 iKuai (WAN2) 的流量。
- IP 地址:
192.168.200.1
- 网卡:
vmbr1
(连接 iKuai WAN2)
- IP 地址:
- WAN: 将处理后的流量发回 iKuai 的 LAN。
- IP 地址:
192.168.100.2
- 网关指向:
192.168.100.1
(iKuai 的 LAN 地址) - 网卡:
vmbr2
(连接 iKuai LAN)
- IP 地址:
- LAN: 接收来自 iKuai (WAN2) 的流量。
PVE 网络设置
iKuai 安装与初始化
虚拟机配置
在 PVE 中为 iKuai 创建虚拟机时,以下是一些关键配置建议:
- 机型:
q35
。提供更现代的硬件特性,是使用 PCIe Passthrough (硬件直通) 的推荐选项。 - BIOS:
默认 (SeaBIOS)
。对 iKuai 兼容性良好。 - SCSI 控制器:
VirtIO SCSI single
。使用半虚拟化驱动 VirtIO 可最大化磁盘 I/O 性能。
安装步骤
从 iKuai 官网下载 32 位 ISO 镜像并上传到 PVE。
新建虚拟机,可以暂时不添加网络设备,稍后统一配置。
硬件直通 (PCI Passthrough): 进入 iKuai 虚拟机的“硬件”菜单,将物理网卡(除 PVE 管理口外)直通给虚拟机。
什么是硬件直通 (PCI Passthrough)?
它允许虚拟机绕过 Hypervisor (PVE) 直接控制物理硬件设备。对于网卡而言,这意味着虚拟机可以获得接近物理机的网络性能和延迟,并能直接利用网卡的硬件特性,是追求极致性能的软路由方案首选。
添加虚拟网卡: 添加
vmbr0
,vmbr1
,vmbr2
这三个 PVE 虚拟网桥作为虚拟网卡。启动虚拟机,iKuai 系统将自动安装。完成后关闭虚拟机,在“选项”中调整引导顺序至硬盘,并移除 ISO 镜像。
重启虚拟机,通过 PVE 控制台初始化 iKuai。根据 PVE 硬件信息中显示的 MAC 地址,将网卡与 iKuai 的接口(如
eth0
,eth1
)一一对应绑定,并设置 LAN 口 IP。
系统内设置
使用 192.168.100.1
访问 iKuai Web 管理界面,完成配置。
- WAN1: 配置为 PPPoE 拨号或 DHCP,作为主外网出口。
- WAN2: 配置为静态 IP,绑定
vmbr1
对应的虚拟网卡。- IP 地址:
192.168.200.2
- 网关:
192.168.200.1
- 关键配置: 将此线路设置为 默认线路。此举的目的是让所有流量在默认情况下都经过透明网关,再通过后续的分流规则将国内流量“豁免”。
- 开启 掉线切换,并设置线路检测,确保透明网关异常时网络可用性。
- IP 地址:
- LAN1:
- 在“高级设置”中,启用 链路桥接,将所有内网接口(物理和虚拟)桥接在一起,创建一个统一的广播域,确保所有设备都在同一局域网内。
配置分流
- 进入 流控分流 > 多线负载,添加自定义运营商。将 china_ip_list 的 IP 段复制进来。由于 iKuai UI 存在输入长度限制,需要将 IP 列表分批添加。
- 添加负载均衡规则,将目标地址为国内 IP 的流量,强制走 WAN1 出口,实现国内流量直连。
添加端口分流规则防止回环
什么是路由回环 (Routing Loop)?
在本架构中,一个数据包的路径可能是:
客户端 -> iKuai -> 透明网关 -> iKuai -> 互联网
。当数据包从透明网关返回 iKuai 时,如果 iKuai 依然按照默认路由(即WAN2
)处理,就会把这个包再次发给透明网关,形成iKuai -> 网关 -> iKuai
的死循环,导致网络中断。
为防止回环,需添加一条规则:将源地址为透明网关 IP (192.168.100.2
) 的所有流量,强制从 WAN1 出口发出。
透明网关
推荐使用 LXC 容器而非完整虚拟机,因为它更轻量,资源开销小,网络性能接近宿主机。我选择 PVE 官方 CT 模板的 debian 12 作为 mihomo 和 dns 服务的运行时。
新建 LXC 容器
LXC 配置文件 (/etc/pve/lxc/111.conf
) 示例:
arch: amd64
cores: 2
features: nesting=1
hostname: gateway
memory: 2048
net0: name=wan0,bridge=vmbr2,gw=192.168.100.1,hwaddr=BC:24:11:B8:D5:64,ip=192.168.100.2/24,type=veth
net1: name=lan0,bridge=vmbr1,hwaddr=BC:24:11:AF:9E:03,ip=192.168.200.1/24,type=veth
ostype: debian
rootfs: local:111/vm-111-disk-0.raw,size=8G
swap: 2048
unprivileged: 1
nameserver: 223.5.5.5
网络配置
编辑 LXC 容器内的 /etc/network/interfaces
,为 lan0
(接收 iKuai 流量)和 wan0
(发回 iKuai)配置静态 IP。
auto lo
iface lo inet loopback
auto lan0
iface lan0 inet static
address 192.168.200.1/24
gateway 192.168.200.2
auto wan0
iface wan0 inet static
address 192.168.100.2/24
Mihomo
安装与配置
- 从 Github Releases 下载二进制文件并放置到
/usr/local/bin/
。 - 创建配置目录
/etc/mihomo
。 - 编写核心配置文件
/etc/mihomo/config.yaml
。与本方案相关的关键配置如下:
# ... (其他配置)
tproxy-port: 7894 # TProxy 监听端口,需与 nftables 脚本一致
routing-mark: 6666 # Mihomo 自身发出流量的标记,用于在 nftables 中豁免,防止代理自身
dns:
enable: true
listen: 0.0.0.0:1053 # DNS 服务监听端口
# ... (其他配置)
服务化 (Systemd)
创建 /etc/systemd/system/mihomo.service
文件。
Systemd Capabilities (权能) 说明
CapabilityBoundingSet
和AmbientCapabilities
是 Linux 的安全特性,用于授予进程精确的权限,而非给予完整的root
权限。
CAP_NET_ADMIN
: 允许程序修改网络接口、路由表、防火墙规则等。TProxy 设置需要此权限。CAP_NET_RAW
: 允许程序使用 RAW 和 PACKET 套接字。CAP_NET_BIND_SERVICE
: 允许程序绑定到 1024 以下的特权端口。这种配置方式比直接使用
User=root
更安全。
[Unit]
Description=Mihomo Daemon, a Clash API compatible core.
After=network.target
[Service]
Type=simple
LimitNPROC=500
LimitNOFILE=1000000
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE
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
TProxy 透明代理
什么是 TProxy?
TProxy (Transparent Proxy) 是 Linux 内核的一项功能,它允许一个应用程序(如 Mihomo)在不修改数据包目的 IP 地址和端口的情况下,接收并处理本应发往其他地址的数据包。相比传统的 REDIRECT (DNAT) 模式,TProxy 能让服务端程序看到真实的客户端源 IP 地址,且对 UDP 的支持更完善,性能也更优。
步骤一:开启 IP 转发
tee /etc/sysctl.conf <<-'EOF'
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
EOF
步骤二:配置防火墙与策略路由
启动脚本: /etc/mihomo/ip-route-poststart.sh
#!/bin/sh
# 1. 在策略路由表 100 中,添加一条默认路由,所有流量从 lan0 发出
ip route add local default dev lan0 table 100
# 2. 添加一条规则:为防火墙标记(fwmark)为 1 的数据包,应用策略路由表 100
ip rule add fwmark 1 lookup 100
# 3. 加载 nftables 防火墙规则集
nft -f /etc/mihomo/nftrules.nft
停止脚本: /etc/mihomo/ip-route-stop.sh
#!/bin/sh
# 按相反顺序清理规则
nft delete table ip clash
ip route del local default dev lan0 table 100
ip rule del fwmark 1 lookup 100
nftables 规则集: /etc/mihomo/nftrules.nft
#!/usr/sbin/nft -f
## 只处理指定网卡的流量,要和ip规则中的接口操持一致
define interface = lan0
## clash的透明代理端口
define tproxy_port = 7894
## clash打的标记(routing-mark)
define clash_mark = 6666
## 常规流量标记,ip rule中加的标记,要和ip规则中保持一致,对应 "ip rule add fwmark 1 lookup 100" 中的 "1"
define default_mark = 1
## 本机运行了服务并且需要在公网上访问的tcp端口(本机开放在公网上的端口),仅本地局域网访问的服务端口可不用在此变量中,以半角逗号分隔
define local_tcp_port = {
22, # ssh,按需设置
8000-9999 # http
}
## 要绕过的局域网内tcp流量经由本机访问的目标端口,也就是允许局域网内其他主机主动设置DNS服务器为其他服务器,而非旁路由
define lan_2_dport_tcp = {
53, 5353, 5354 # dns查询
}
## 要绕过的局域网内udp流量经由本机访问的目标端口,也就是允许局域网内其他主机主动设置DNS服务器为其他服务器,而非旁路由;另外也允许局域网内其他主机访问远程的NTP
服务器
define lan_2_dport_udp = {
53, 5353, 5354, # dns查询
123 # ntp端口
}
## 保留ip地址
define private_address = {
127.0.0.0/8,
100.64.0.0/10,
169.254.0.0/16,
224.0.0.0/4,
240.0.0.0/4,
10.0.0.0/8,
172.16.0.0/12,
192.168.0.0/16
}
table ip clash {
## 保留ipv4集合
set private_address_set {
type ipv4_addr
flags interval
elements = $private_address
}
## prerouting链
chain prerouting {
type filter hook prerouting priority filter; policy accept;
ip protocol { tcp, udp } socket transparent 1 meta mark set $default_mark accept # 绕过已经建立的连接
meta mark $default_mark goto clash_tproxy # 已经打上default_mark标记的属于本机流量转过来的,直接进入透明代理
fib daddr type { local, broadcast, anycast, multicast } accept # 绕过本地、单播、组播、多播地址
tcp dport $lan_2_dport_tcp accept # 绕过经由本机到目标端口的tcp流量
udp dport $lan_2_dport_udp accept # 绕过经由本地到目标端口的udp流量
ip daddr @private_address_set accept # 绕过目标地址为保留ip的地址
goto clash_tproxy # 其他流量透明代理到clash
}
## 透明代理
chain clash_tproxy {
ip protocol { tcp, udp } tproxy to :$tproxy_port meta mark set $default_mark
}
## output链
chain output {
type route hook output priority filter; policy accept;
oifname != $interface accept # 绕过本机内部通信的流量(接口lo)
meta mark $clash_mark accept # 绕过本机clash发出的流量
fib daddr type { local, broadcast, anycast, multicast } accept # 绕过本地、单播、组播、多播地址
udp dport { 53, 5353, 123 } accept # 绕过本机dns查询、NTP流量
tcp sport $local_tcp_port accept # 绕过本地运行了服务的tcp端口,如果并不需要从公网访问这些端口,可以注释掉本行
ip daddr @private_address_set accept # 绕过目标地址为保留ip的地址
ip protocol { tcp, udp } meta mark set $default_mark # 其他流量重路由到prerouting
}
}
步骤三:集成到 systemd 服务
在 /etc/systemd/system/mihomo.service
加入声明周期脚本,令 systemd 维护 mihomo 的时候自动执行:
ExecStartPost=/etc/mihomo/ip-route-poststart.sh
ExecStop=/etc/mihomo/ip-route-stop.sh
DNS
DNS 查询链
本方案构建了一个“责任链模式”的 DNS 解析流程:
客户端 -> AdGuard Home -> SmartDNS -> 最终上游 DNS
。每个环节只做自己的专职工作:AdGuard Home 负责过滤广告和黑名单,SmartDNS 负责对国内外域名进行智能、快速的解析。这种分层设计使得结构清晰,易于排错和维护。
- 安装 SmartDNS:
apt install smartdns
。配置好国内外两组上游 DNS 服务器。为获得最佳性能,禁用测速 (speed-check-mode none
) 并开启缓存持久化。 - 安装 AdGuard Home: 在 AdGuard Home 的上游 DNS 设置中,仅填入 SmartDNS 的监听地址(如
127.0.0.1:5353
)。关闭 AdGuard Home 的查询缓存,避免与 SmartDNS 重复缓存。 - 整合: 在 iKuai 的 DHCP 服务 -> LAN 口设置 中,将主 DNS 服务器地址修改为透明网关的地址:
192.168.200.1
。这样所有内网设备获取到的 DNS 服务器就是 AdGuard Home。
自动更新配置
为了实现低维护运行,各类配置应尽可能自动化更新。
- iKuai 大陆 IP 分流: 手动更新即可,IP 列表变动不频繁。
- Mihomo 订阅配置: 推荐部署私有 sub-store 用于聚合。在透明网关中设置
cron
定时任务,定期wget
新的配置文件并systemctl restart mihomo
。 - SmartDNS 国内域名列表: 定时任务从 Olixn/china_list_for_smartdns 等项目下载更新列表并重启 SmartDNS。
- AdGuard Home 过滤规则: 直接在 AdGuard Home 的 Web UI 中订阅优秀的过滤列表即可自动更新。
- AdGuard Home 过滤规则自定义规则同步: TODO。