基于虚拟机的单网口软路由实践
date
Mar 15, 2022
slug
5Z+65LqO6Jma5ouf5py655qE5Y2V572R5Y+j6L2v6Lev55Sx5a6e6Le1
status
Published
tags
Tech
summary
一直以来都很想搭建一台多功能家庭服务器,以实现软路由、NAS、媒体中心、下载机、远程桌面办公等功能的一体化。
type
Post
背景
一直以来都很想搭建一台多功能家庭服务器,以实现软路由、NAS、媒体中心、下载机、远程桌面办公等功能的一体化。
刚好最近又添置了一台新的设备作为主力机,那么之前的主力机 NUC11 就“闲置”了。本来打算将这台机器出掉回回血,但转念一想,这台机器搭载了功耗相对较低的移动端处理器 i5-1135G7、16 GB DDR4 内存、一个 1TB NVME 硬盘、一个 1TB HDD 硬盘,以及一个 2.5G 网口,如果将其打造成一台多功能的家庭服务器,物尽其用的同时,作为一台小主机,其较强的性能也可保证未来相当长一段时间内不会落伍。
于是便有了这篇文章。
系统
这台服务器采用了 Windows 11 操作系统,通过各种软件以及 Hyper-V 虚拟机拓展使用场景。

之所以做了这个非常规的违背祖宗的决定,也是基于多个因素综合考虑的结果。
家庭服务器的操作系统,大概有三个主流的选择:Linux、PVE/ESXI/unRaid 虚拟机、Windows Server 等。
关于 Linux,我个人是一个 Linux 桌面的长期使用者,使用经验也相对丰富,并且 Linux 也占据了服务器市场的绝大部分份额,使用 Linux 作为服务器是应有之义。但是 Linux 有一个致命的问题,那就是软件生态的匮乏(“家庭”服务器的使用场景)。举个例子,比如作为下载机,在国内很难完全绕开迅雷,虽然 Linux 桌面也有原生的迅雷(甚至 flatpak 版本还是我维护的),但是缺失了比如迅雷云盘等功能,实用性大打折扣。遂无奈放弃。
关于 PVE/ESXI/unRaid 等虚拟机,没有选择这个方案一方面是因为之前没接触过,还得从头研究,比较消耗脑细胞;最关键的一点是,如果不直通显卡等硬件(至少目前 NUC11 的显卡无法直通),图形性能严重不足,那么这颗 80EU 的 Xe 显卡性能就浪费了。遂果断放弃。
关于 Windows Server,这本来是我的首选方案,服务器系统相对稳定,也具备 Windows 软件生态最为丰富的优势,还能完美驱动各个硬件设备。可是折腾了半天,有线网卡驱动死活装不上,我知道一般是我自己操作的问题,但是最终还是没能解决,网卡驱动不起来,做服务器便是虚妄。遂自闭放弃。
于是选择了 Windows 11 作为服务器的操作系统。其实任何一台机器,任何一个系统,只要能够实现相应的目的,那么就可以作为一台“服务器”,条件没必要卡的那么死。像这样,直接在 host 上安装闪电下载、迅雷等实现下载机的功能;安装 Emby 实现家庭媒体中心的功能;使用自带的远程桌面实现远程办公的功能;使用自带的文件共享实现 NAS 的功能;最关键的,跑一个 Hyper-V 虚拟机装一个 OpenWrt 系统,实现软路由的各种功能,比如局域网内手机、平板、笔记本等其他设备的全局透明代理。
基于虚拟机的单网口软路由实践
前戏有点长,终于来到了本文题目的内容。
简单讲,是用一根网线连接 NUC 的 2.5G 网口和普通硬路由器的 LAN 口,再在 NUC 的 Windows 11 系统上启动一个装有 OpenWrt 路由器系统的 Hyper-V 虚拟机,并以桥接的方式连接。这样,原本连接普通硬路由 Wi-Fi 的设备如不做额外设置,则不会受到任何影响,而希望通过 OpenWrt 全局透明代理的设备,依旧是连接原本的 Wi-Fi,只需将网关和 DNS 改为此虚拟机,即可使网络流量穿过装有代理工具的虚拟机软路由。

需要注意的是,最好为 host 分配一个静态地址,以方便后续操作。
准备 OpenWrt 系统镜像
到 OpenWrt 的 releases 页面选择所需镜像(这里是 x86_64,注意选择正确的架构),这里我就选择
generic-ext4-combined-efi.img.gz
,下载得到 openwrt-版本号-x86-64-generic-ext4-combined-efi.img.gz
。将上述镜像解压,得到
openwrt-版本号-x86-64-generic-ext4-combined-efi.img
。到这里,还需要将此 img 镜像转换为适用于 Hyper-V 虚拟机的 vhdx 格式。这里我选择 StarWind V2V Converter 进行格式转换。下载完成后安装打开。
- 在 Select location of image to convert 界面,选择 Local file
- 在 Source image 界面,选择刚解压得到的 img 镜像
- 在 Select location of destination image 界面,选择 Local file
- 在 Select destination image format 界面,选择 VHD/VHDX
- 在 Select option for VHD/VHDX image format 界面,选择 VHDX growable image
- 在 Set destination file name 界面,选择文件保存地址,默认与源文件同目录
最终得到名为
openwrt-版本号-x86-64-generic-ext4-combined-efi.vhdx
的文件。安装 Hyper-V 虚拟机
在开始菜单搜索“启用或关闭 Windows 功能”,找到 Hyper-V 勾选安装,重启以完成安装。此处不再赘述。
创建并配置 OpenWrt 虚拟机
在开始菜单搜索并打开“Hyper-V 管理器”,点击右侧的“虚拟交换机管理器”。

在弹出的窗口中,“新建虚拟网络交换机”,在右侧窗口中选择“外部”,并点击“创建虚拟交换机”,之后为该虚拟交换机起一个名字,比如“Bridge Switch”,外部网络选择 host 正在使用的网卡,记得勾选“允许管理操作系统共享此网络适配器”。


回到 Hyper-V 管理器主界面,点击右侧的“新建-虚拟机”打开“新建虚拟机向导”。

需要注意的是,在“指定代数”这一步,如果之前的镜像是含有
efi
字样的,那么选择“第二代”,否则选“第一代”;
在“配置网络”这一步,选择刚刚建立的虚拟网卡;

在“连接虚拟硬盘”这一步,选择“使用现有虚拟硬盘”并选择之前转换得到的拓展名为
vhdx
的文件。
其他选项保持默认即可。
再次回到 Hyper-V 管理器主界面,在刚刚创建的虚拟机上“右键-设置”,打开该虚拟机的设置页面,在左侧找到“安全”,并禁用安全启动。


在设置完成的虚拟机上“右键-启动”、“右键-连接”,即可启动 OpenWrt 并看到输出。待输出内容稳定后,敲一下回车,即可输入后续命令。
首先,键入
passwd
以修改管理员密码;之后,键入
vim /etc/config/network
以修改基本配置;只需修改
config interface 'lan'
部分的内容。option ipaddr '192.168.1.1'
代表路由器管理界面地址,默认为 192.168.1.1
,建议修改为与 host 同一网段的其他可用固定 IP 地址; 之后,在后面增加两行:gateway
意为网关,dns
配置 DNS,将二者统一设置为 host 所连接的物理硬路由器的 IP 地址(比如我用的华为路由器,地址为 192.168.3.1)。参考配置如下图。
使用局域网内另一台设备的浏览器输入设置好的路由器管理地址,再输入账号密码即可打开 OpenWrt 软路由的管理页面了。

安装 OpenClash
在这里,我选用 OpenClash 实现代理功能。
根据 OpenClash 的 Wiki 安装 OpenClash 所需依赖。
首先,更新软件包:
之后,安装上文所述页面规定的依赖:
需要注意的是,OpenClash 所需的
dnsmasq-full
与系统自带的 dnsmasq
冲突,安装之前需要先卸载掉系统自带的包,所以这一步这样执行:安装其他包的时候也可能出现一些报错,忽略即可。
将该文件上传至 OpenWrt 虚拟机,比如我的虚拟机软路由地址为
192.168.3.199
,在 macOS 下可执行:随后在虚拟机里执行:
从而将内核文件放置在正确的位置并给予其可执行权限。
在 这里 下载 OpenClash 的安装包,比如
luci-app-openclash_0.44.29-beta_all.ipk
,随后打开虚拟机路由器的管理页面,进入“System-Software”页面,并点击“Upload Package...”按钮上传并安装刚刚下载好的 OpenClash 安装包。

稍等片刻,安装完成后(这里可能有报错,依旧忽略即可),重启 OpenWrt 虚拟机,并再次进入虚拟机路由器管理页面,此时,应该已经出现了 OpenClash 服务。

在“Config Update”标签页配置完成 Clash 订阅后,回到“Overviews”标签页,点击界面左下角的“启动 OpenClash”即可开启代理服务。


此时,打开同一局域网内其他设备的网络设置,将网关和 DNS 均配置成 OpenWrt 虚拟机软路由的地址,即可实现全局透明代理。


打开浏览器,输入
https://www.google.com/
,完成~
最后
全局透明代理的体验真的非常棒,不用再单独为浏览器、Telegram、Spotify、终端等单独设置代理,也不用再为一些没有代理设置选项的软件所困扰。
此外,因为这台 NUC11 是以有线方式连接到路由器上的,所以局域网访问速度和稳定性都得到了一定程度的保障,使用远程桌面管理服务器时也十分流畅。不得不说,微软的 Microsoft Remote Desktop 可以称得上最好的远程桌面客户端,比如分辨率问题,只需勾选 Optimize for Retina displays 即可完美解决。

补充(2022.03.21)
最近几天一直使用全局代理,上网一切正常。然而,我发现不使用代理的时候,无法正常访问互联网。我本来以为旁路网关对局域网其他设备不会有影响,但事实证明我错了,不仅有影响,而且非常大。
OpenWrt 作为旁路由,需要注意两个坑:
- 局域网内禁止存在多个 DHCP 服务器。主路由已经提供了 DHCP 服务,故需关闭作为旁路由的 OpenWrt 的 DHCP 服务。
关闭方法:网络 - 接口 - 接口 - LAN - 编辑 - DHCP 服务器 - 常规设置 - 忽略此接口

需要注意的是,作为旁路网关使用时,不可完全停用 Dnsmasq,因而不能采用到 网络 - DHCP/DNS 选项卡中关闭的方法。
- 因为较新的系统会优先使用 IPv6 网络,所以需要禁用 LAN 口的 IPv6 服务,以避免局域网设备获得了多个临时 IPv6 地址从而导致无法正常联网。
禁用方法:网络 - 接口 - 设备 - br-lan - 配置... - 启用 IPv6(取消勾选)

参考文章:
等等...