软路由相关
PVE 部署 mihomo 旁路由(透明代理)详细教程:从零开始,只需 PVE 和订阅链接
PVE LXC 部署 mihomo 旁路由(透明代理)详细教程
> 目标:用一台 PVE 上的轻量 LXC 容器跑 mihomo,做成"旁路由"。指定设备把网关和 DNS 指向它,就能实现国内直连、国外走机场节点,并且可以按应用分流。
> 适用版本:PVE 7 / 8 / 9(本文命令在 PVE 9.2.10 实测通过);容器用 Debian 12 模板。
> 你只需要:一台 PVE、一个 Clash 格式的节点订阅链接、一台支持 DHCP 的主路由(爱快 / OpenWrt / 任意路由器)。
> ⚠️ 先说清楚地址问题:下文所有
http://10.10.10.2/... 是作者内网服务器上存放配套文件的地址。你在自己的环境里,要把这些配套文件放到你自己能访问的位置,并把所有 10.10.10.2 替换成你自己的地址。一、准备清单
1. 配套文件(要放到你自己能访问的 Web 服务器上)
| 文件 | 用途 | 说明 |
|---|---|---|
pgw-install.sh | 容器内一键安装脚本(mihomo + 面板 + 配置 + 开机自启) | 必装 |
pgw-mihomo.yaml | 基础版配置:国内直连,国外统一走选中节点 | 安装脚本内置,无需手动下载 |
pgw-mihomo-split.yaml | 分流版配置:TikTok / AI 固定新加坡,各应用独立分组 | 可选,第十节用 |
pgw-deploy.zip | 以上文件打包 | 方便一次性下载 |
pve-mihomo-oneclick.sh | PVE 宿主机一键部署脚本(自动建 LXC + 放行 TUN + 装 mihomo) | 下载 |
> 注意:
pgw-deploy.zip 里的分流版配置可能比单独文件旧,需要最新版请单独下载 pgw-mihomo-split.yaml。2. 节点订阅
一个 Clash 格式的订阅链接(机场后台复制的那种),例如本文用
http://10.10.10.2/yaml/sub-clash.yaml。请换成你自己的。3. 主路由
任意支持 DHCP 的路由器即可。本文用爱快做示例。
> 不需要会 PHP、不需要编译、不需要写 Clash 规则——下面的命令全部复制即可。
二、架构原理
flowchart LR
A[客户端设备] -->|网关/DNS 指向旁路由| B[PVE LXC 容器<br/>mihomo TUN 透明代理]
B --> C[主路由]
C --> D[国内直连]
C --> E[境外走选中节点]
- 主路由:负责 DHCP 和正常上网,平时什么都不用改;
- 旁路由(LXC 里的 mihomo):用 TUN 设备透明接管"被指了网关"的设备的流量,按规则分流;
- 节点:来自订阅链接,在面板里手动选,或自动选延迟最低的。
三、快速方式:一键脚本(推荐)
不想手动一步步来?PVE 宿主机上一条命令跑完"建 LXC + 放行 TUN + 安装 mihomo + 面板":
# PVE 宿主机(root 执行)
wget -qO /tmp/pve-mihomo-oneclick.sh http://10.10.10.2/blog/uploads/yaml/pve-mihomo-oneclick.sh
bash /tmp/pve-mihomo-oneclick.sh --check # 先只读检查环境,不会创建任何东西
bash /tmp/pve-mihomo-oneclick.sh 200 pgw-2026 pgw vmbr0
参数依次是:容器 ID、面板密码、主机名、网桥。脚本会自动探测模板和存储,完成:
跑完直接跳到第八节配主路由即可。想手动一步步来,继续看下面第四~六节。
> 默认用 DHCP 自动拿 IP;想要固定 IP,就在最后加一个参数,例如
bash /tmp/pve-mihomo-oneclick.sh 200 pgw-2026 pgw vmbr0 10.10.10.200。固定 IP 时网关自动取 PVE 的默认网关,也可用环境变量 PGW_GW 覆盖。四、PVE 宿主机:创建 LXC 容器
以下命令在 PVE 宿主机的 shell(网页控制台或 SSH)执行。模板名和存储名不要手写死,让命令自动找:
# 1. 更新模板源,自动选一个 Debian 12/11 模板
pveam update
TPL=$(pveam available | tr ' ' '\n' | grep -E '^debian-1[12]-standard.*amd64\.tar\.zst$' | head -n1)
echo "选用模板: $TPL"
pveam download local "$TPL"
# 2. 自动找一个能放容器磁盘的存储
STORE=$(pvesm status -content rootdir | awk 'NR>1{print $1; exit}')
echo "选用存储: $STORE"
# 3. 创建容器:eth0 桥接 vmbr0,DHCP 从主路由自动拿地址
pct create 200 "local:vztmpl/$TPL" \
--hostname pgw \
--memory 512 --swap 0 --cores 1 \
--net0 name=eth0,bridge=vmbr0,ip=dhcp \
--rootfs "$STORE:4" \
--features nesting=1 \
--unprivileged 0
# 4. 启动
pct start 200
说明:
--unprivileged 0 是特权容器。旁路由需要 TUN 设备,特权容器最省事(本文方案基于特权容器)。pgw,都可以按喜好改。常见报错:
| 报错 | 处理 |
|---|---|
template: no such template | 模板版本号不对,用上面的自动选择即可 |
storage 'local-lvm' does not exist | 你的存储不叫这个名字,用 pvesm status -content rootdir 找实际可用的 |
bridge vmbr0 相关报错 | 用 ip a 看你实际的网桥名,把 vmbr0 替换掉 |
五、PVE 宿主机:放行 TUN 设备(必做,跳过则透明代理不生效)
这一步在 PVE 宿主机执行。注意:刚创建好的容器里本来就没有 /dev/net/tun,这是正常的,先把配置加上再重启验证:
# 1. 确保宿主机有 tun 模块和设备
modprobe tun
ls -l /dev/net/tun
# 2. tun 模块开机自动加载
echo tun >> /etc/modules-load.d/tun.conf
# 3. 给容器放行 TUN 设备并挂载(永久生效)
cat >> /etc/pve/lxc/200.conf <<'EOF'
lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file
EOF
# 4. 重启容器
pct reboot 200
重启后验证(在 PVE 宿主机执行):
pct exec 200 -- ls -l /dev/net/tun
能看到
/dev/net/tun 设备即成功。> 如果不做这一步,mihomo 日志会报
Start TUN listening error: configure tun interface: no such file or directory,面板能开但透明代理不生效。六、容器内:一键安装 mihomo + 面板
先在 PVE 宿主机进入容器,再执行安装:
pct enter 200
在 容器内执行(把最后的
pgw-2026 换成你自己的面板密码,建议只用字母数字):wget -qO /tmp/pgw-install.sh http://10.10.10.2/blog/uploads/yaml/pgw-install.sh && bash /tmp/pgw-install.sh pgw-2026
脚本会自动完成 7 步:
net.ipv4.ip_forward=1跑完会打印类似这样的信息:
旁路由 IP : 10.10.10.100
节点面板 : http://10.10.10.100:9090/ui 密码: pgw-2026
客户端设置 : 网关 = 10.10.10.100 , DNS = 10.10.10.100
(IP 是你的容器从 DHCP 实际拿到的地址,示例里的 10.10.10.100 换成你自己的。)
安装后马上确认三件事(容器内):
systemctl is-active mihomo # 应输出 active
/usr/local/bin/mihomo -v # 显示内核版本
curl -s -H "Authorization: Bearer pgw-2026" http://127.0.0.1:9090/version
最后一条应返回类似
{"meta":true,"version":"v1.19.30"}。如果面板密钥不是 pgw-2026,Bearer 后面换成你的密码。七、连接面板
浏览器打开
http://旁路由IP:9090/ui,在弹出的设置里填:http://旁路由IP:9090如果面板提示"后端无法连接 / unauthorized",都是这两个值不对,改对即可。
连上后能看到订阅里的全部节点(按协议分组)和两个策略组:🚀 节点选择(手动选)、♻️ 自动选择(自动测速)。
八、主路由配置(爱快示例):把设备指到旁路由
这一步在主路由(爱快)里做:
> 其他路由器同理:要么把某台设备的默认网关/DNS 手动改成旁路由 IP,要么在 DHCP 里按设备指定。
九、验证
在被指了网关的设备上:
在旁路由容器内也可以直接测代理链路:
curl -s -o /dev/null -w "%{http_code}\n" -x http://127.0.0.1:7890 https://www.gstatic.com/generate_204
返回
204 说明节点链路正常。十、按应用分流(可选)
基础版只有一个总开关(国外统一走选中节点)。想按应用分流,换成
pgw-mihomo-split.yaml:# 容器内执行
cp /etc/mihomo/config.yaml /etc/mihomo/config.yaml.bak
wget -qO /etc/mihomo/config.yaml http://10.10.10.2/blog/uploads/yaml/pgw-mihomo-split.yaml
sed -i 's/CHANGEME/pgw-2026/' /etc/mihomo/config.yaml
/usr/local/bin/mihomo -t -d /etc/mihomo -f /etc/mihomo/config.yaml # 校验配置,无输出即通过
systemctl restart mihomo
>
sed 里的 pgw-2026 换成你自己的密码。密码含 / 或 & 会导致替换出错,所以建议用纯字母数字。分流版分组:
| 分组 | 默认出口 |
|---|---|
| 🎵 TikTok、🤖 AI | 🇸🇬 新加坡 |
| 🍀 Google/YouTube、👨🏿💻 GitHub、📲 Telegram、🪟 Microsoft/OneDrive、💶 PayPal | 🚀 默认代理(自动测速) |
| 🐟 漏网之鱼 | 🚀 节点选择 |
| 国内域名/IP | 直连 |
十一、故障排查
| 现象 | 原因与处理 |
|---|---|
| mihomo 报 TUN 错误 | 没放行 /dev/net/tun,回第五节操作 |
| 面板提示后端无法连接 | 后端地址要填 http://旁路由IP:9090,不是 127.0.0.1;密钥要和安装时一致 |
| 面板里没有节点 | 容器里先测订阅是否可达:curl -I http://10.10.10.2/yaml/sub-clash.yaml |
| 改了配置没变化 | 记得 systemctl restart mihomo |
| 设备提示无 Internet | 确认 TUN 已启用、msftconnecttest / msftncsi 直连规则在(基础配置已内置) |
| 某些节点连不上 | 换协议试试(vless / vmess 兼容性最好),或等节点恢复 |
| nslookup 超时 / SERVFAIL | DNS 没监听 53 或上游不可达。检查配置里 dns.listen: 0.0.0.0:53,上游用国内可达的阿里 DoH(dns.alidns.com),不要用 dns.google |
| Windows 显示"IPv4 未连接" | NCSI 探测走了代理,把 131.107.255.255 加入直连规则(基础配置已内置) |
十二、回滚 / 卸载
systemctl disable --now mihomo;pct stop 200 && pct destroy 200(会连同容器磁盘一起删,建议先备份配置)。附录:基础版配置全文(与 pgw-mihomo.yaml 一致)
mixed-port: 7890
allow-lan: true
bind-address: "*"
mode: rule
log-level: info
ipv6: false
unified-delay: true
tcp-concurrent: true
external-controller: 0.0.0.0:9090
external-ui: /etc/mihomo/ui
secret: "改成你的面板密码"
geodata-mode: true
geo-auto-update: true
geox-url:
geoip: "https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat"
geosite: "https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat"
mmdb: "https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/country.mmdb"
profile:
store-selected: true
store-fake-ip: true
tun:
enable: true
stack: system
dns-hijack: ["any:53", "tcp://any:53"]
auto-route: true
auto-redirect: true
auto-detect-interface: true
dns:
enable: true
listen: 0.0.0.0:53
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
default-nameserver: [223.5.5.5, 114.114.114.114]
nameserver:
- https://dns.alidns.com/dns-query
- 223.5.5.5
proxy-server-nameserver:
- https://dns.alidns.com/dns-query
direct-nameserver:
- 223.5.5.5
- 114.114.114.114
respect-rules: true
fake-ip-filter:
- "+.msftconnecttest.com"
- "+.msftncsi.com"
proxy-providers:
airport:
type: http
url: "http://10.10.10.2/yaml/sub-clash.yaml"
interval: 86400
health-check: {enable: true, url: "https://www.gstatic.com/generate_204", interval: 300}
path: ./providers/airport.yaml
proxies:
- {name: 直连, type: direct}
- {name: dns, type: dns}
proxy-groups:
- name: 🚀 节点选择
type: select
include-all: true
filter: "(?i)^((?!(直连|dns)).)*$"
- name: ♻️ 自动选择
type: url-test
url: "https://www.gstatic.com/generate_204"
interval: 300
tolerance: 50
include-all: true
filter: "(?i)^((?!(直连|dns)).)*$"
rules:
# Windows / 手机连通性探测必须直连,避免"无 Internet"误报
- DOMAIN-SUFFIX,msftconnecttest.com,DIRECT
- DOMAIN-SUFFIX,msftncsi.com,DIRECT
- IP-CIDR,131.107.255.255/32,DIRECT,no-resolve
- IP-CIDR6,fd3e:4f5a:5b81::1/128,DIRECT,no-resolve
# 国内直连
- GEOSITE,cn,直连
- GEOIP,CN,直连
# 其余全部走你选的节点
- MATCH,🚀 节点选择
需要改的就两处:
secret(面板密码)和 proxy-providers.airport.url(你的订阅地址)。
评论(0)