1 先纠正两个误区:TUN 在宿主机上,不等于虚拟机自动分流
在 Linux 宿主机上给 Mihomo 或 Clash 兼容内核开 TUN,接管的是宿主机本机发出的 IP 包路径;QEMU/KVM 客户机拥有独立的网络命名空间与路由表,其流量先经过虚拟网卡与 libvirt 定义的转发域,再出到物理网络。除非你在宿主机上做额外的转发、策略路由或透明代理,否则「宿主机 TUN 已开」并不能让虚拟机里的 apt、docker pull 自动获得与桌面浏览器相同的策略。
第二个误区是把默认网关当成「代理开关」。在 libvirt 默认 NAT 里,客户机的默认网关通常指向 virbr0 上的宿主机侧地址(常见为 192.168.122.1),它负责把私网地址做 SNAT 后转发出去;这与「把 HTTP 交给 Mihomo 的混合端口」不是同一层功能。你要的是:虚拟机进程能否TCP 连到宿主机上监听的 7890(示例端口,以你配置为准)一类入站,并在应用层把代理指过去。
因此与站内《Hyper-V 虚拟机走宿主机 Clash》、《VMware NAT 与桥接》等文一致:先定拓扑(NAT 还是用户态),再定代理地址写谁,最后才考虑要不要动路由或做 DNAT。
2 libvirt 默认 NAT(virbr0):虚拟机里「宿主机」通常是谁
virt-manager 新建虚拟机时若选用默认网络,一般会挂到名为 default 的 libvirt 网络上,宿主机侧接口多为 virbr0,网段常见为 192.168.122.0/24,网关地址常为 192.168.122.1。对客户机而言,这就是默认路由下一跳;同时,它也是你从客户机访问宿主机上服务时最常填写的「宿主机 IP」(与 Windows Hyper-V 默认交换机里「网关即 NAT 端」同一逻辑)。
在宿主机上可用下面命令核对当前 default 网络的 XML 与地址分配(输出以你机器为准):
virsh net-info default
ip -br addr show virbr0
若你自定义过网络名称或网段,请以 virsh net-dumpxml 中的 ip address 为准,不要死记文档里的示例数字。桥接到物理网卡时,客户机与宿主机可能在同一局域网网段,此时应改用宿主机在物理网段上的 IPv4 作为代理目标,并同样保证 Mihomo 监听在可达接口上。
3 用户模式网络(user / slirp):记住 10.0.2.2
当虚拟机使用 QEMU user networking(旧称 slirp)而非 libvirt 的 NAT 网桥时,客户机常见地址在 10.0.2.0/24,其中 10.0.2.2 是 QEMU 约定给宿主机的别名。此时你应把代理写成 http://10.0.2.2:端口 一类形式,而不是 192.168.122.1,也不要写 127.0.0.1——在客户机内部环回永远指向客户机自己。
用户模式网络的局限是性能与协议支持不如 tap/bridge,且端口映射需通过 hostfwd 等参数显式声明;但它不依赖宿主机桥接权限,在笔记本或受限环境做快速开发机时很常见。virt-manager 里若选择「NAT」而非「用户态」,通常走的是 libvirt 管理的网桥,与上一节的 virbr0 模型更一致,二者不要混用教程里的 IP。
ip route show default:若下一跳是 192.168.122.1 一类私网且能 ping 通 virbr0 网段,多半是 libvirt NAT;若网卡地址落在 10.0.2.0/24 且文档提到 user,优先尝试 10.0.2.2。
4 宿主机 Mihomo:bind-address、Allow LAN 与 Linux 防火墙
在改虚拟机之前,请先在宿主机确认 Mihomo(或图形客户端包装的同一内核)是否对虚拟网卡所在网段开放入站。配置文件中的 bind-address 若为 127.0.0.1,则只有本机环回可连;需要客户机访问时,应使用 0.0.0.0 或明确写成 192.168.122.1 等可达地址,并打开界面中的 Allow LAN 或等价选项,使混合端口监听在非环回地址上。
Linux 宿主机若启用 nftables、firewalld 或发行版自带防火墙,可能默认丢弃来自 virbr0 转发面的入站 TCP。可用 ss -tlnp | grep 7890(端口替换为你的混合端口)确认监听范围,再在防火墙中为该端口做最小放行,仅面向 192.168.122.0/24 等信任网段。systemd 常驻与最小 YAML 可参考本站《Linux 安装 Mihomo 并开机自启》。
若 Mihomo 只跑在 Docker 里,还要注意 published port 是否绑定在 0.0.0.0,以及客户机到 docker0 或宿主机 published 地址的路径是否与 libvirt 路由冲突——这类组合拓扑建议画一张简图再改规则,避免「宿主机 curl 通、虚拟机不通」的假象。
5 配法一(推荐):在虚拟机内显式使用宿主机代理
适用场景:apt、curl、git、浏览器、以及尊重 HTTP_PROXY 环境变量的容器构建;不要求客户机内每一个原始 IP 包都经宿主机策略路由。
在 Linux 客户机中为当前会话导出环境变量(将 HOST 替换为 192.168.122.1 或 10.0.2.2,端口以 Mihomo 为准):
export http_proxy="http://HOST:7890"
export https_proxy="http://HOST:7890"
curl -I --proxy "$http_proxy" https://www.google.com
apt 建议在 /etc/apt/apt.conf.d/95proxy.conf 中写入 Acquire::http::Proxy 与 Acquire::https::Proxy,不要假设 http_proxy 一定被所有后端使用。Podman/Docker 拉镜像可在 /etc/systemd/system/docker.service.d/ 下用 Environment=HTTP_PROXY=... 注入,或为 docker pull 单次加 --build-arg 一类机制,与 CI 文档保持一致。
图形桌面可在「网络代理」中填写同一宿主机地址;与 Windows 虚拟机教程不同,Linux 客户机没有 WinHTTP,但不走代理的守护进程仍然大量存在,需按应用单独配置。
virbr0 网段,便于对照规则与 DNS 是否命中。
6 配法二:宿主机端口转发(hostfwd / DNAT)何时用
有时你希望客户机内某应用硬编码连本机环回(例如只认 127.0.0.1:7890),或需要在 user 网络下把宿主机某端口映射进客户机。可以在 QEMU 参数中使用 hostfwd=tcp::17890-:7890 这类语法,把宿主机 TCP 17890 转到客户机内 7890;方向与端口请以官方文档为准,这里只强调转发与代理是两条不同管道,不要与「客户机直连宿主机混合端口」混谈。
在 libvirt NAT 场景,更常见需求是反向:外网或局域网访问虚拟机服务,用 libvirt 的 hook 或 iptables/nft 在 virbr0 上做 DNAT。若你坚持让客户机内应用访问「宿主机上的 127.0.0.1 服务」,可在宿主机用 socat 把 virbr0 地址上的 TCP 转发到环回口的 Mihomo——这属于进阶运维,需自行评估暴露面与认证。
对大多数「复用宿主机已配好的 Mihomo」的开发需求,配法一已足够;只有在应用无法改代理地址、或需要与现有编排模板对齐时,才值得引入 hostfwd/DNAT 的维护成本。
7 virt-manager 与桥接:和 Windows 宿主机场景区分
在 virt-manager 中切换「NAT」「桥接到 eth0」「macvtap」等选项,本质是更换客户机虚拟网卡后端:桥接时客户机像插在交换机上的第二台物理机,宿主机 IP 应取物理网卡地址;NAT 与用户态则取上一节所述约定网关侧地址。这与 Hyper-V、VMware 系列文章中的「默认 NAT vs 桥接」叙述一一对应,只是 Linux 侧工具换成了 libvirt 与 ip route。
若你在同一台机器上同时跑 Kubernetes、Docker 与 KVM,注意多条默认路由与策略路由表是否互相覆盖;Mihomo TUN 与 CNI 网桥并存时,建议先用「客户机显式代理」验证连通,再考虑更复杂的宿主侧转发。
8 验证步骤与常见失败原因
建议按顺序执行,避免同时修改防火墙、YAML 与客户机环境变量后无法归因。
- 客户机内
ip route show default,确认下一跳与本文拓扑判断一致。 - 客户机
curl -v --proxy http://GATEWAY_IP:PORT https://example.com,确认 TCP 与 TLS 成功。 - 宿主机
ss -tlnp核对 Mihomo 监听地址是否包含0.0.0.0:PORT或网关 IP。 - 查看 Mihomo 日志是否有来自客户机网段的入站;若无,优先查防火墙与 bind-address。
- DNS 异常时对照《DNS 防泄漏》,确认客户机未绕过 Mihomo 的 DNS 入口。
高频失败原因包括:把代理写成 127.0.0.1;未开 Allow LAN;用户态与 libvirt NAT 的 IP 混用;仅设置了 shell 环境变量但 sudo apt 清空了代理;以及 firewalld 拒绝 virbr0 入站。
9 总结
QEMU/KVM 在 Linux 宿主机上复用 Mihomo,关键是先分清libvirt NAT 与用户模式网络:前者多在 virbr0 网段用网关地址访问宿主机,后者常用 10.0.2.2。宿主机的 TUN 不会自动替客户机分流;最稳妥的路径是在客户机内为 apt、容器引擎与终端显式配置 HTTP(S) 代理,并保证宿主机混合端口对虚拟网段监听且防火墙放行。
端口转发与 DNAT 适合无法改代理地址或需要与现有端口编排对齐的场景,但维护成本更高。与站内 WSL2、Hyper-V、VMware、Parallels 等专题并列,本文补齐了裸机 Linux + KVM这一常见栈,便于你在同一套 Mihomo 规则下覆盖桌面、服务器与虚拟机开发环境。
相比在客户机里反复试错默认路由,在宿主机用图形或 YAML 把监听地址、Allow LAN 与日志一次理顺,再配合客户机侧最小代理配置,整体排障时间通常更短;Clash 兼容内核在规则可读性上的优势,也会延续到多虚拟机并行开发场景。
相比其他同类工具,Mihomo 与 Clash 系在 Linux 服务端与桌面端的文档与社区实践都更连贯;把宿主机监听接口与客户机代理地址对齐后,apt 与镜像拉取会稳定很多。