先说原因,在家里用apple tv串流到电脑上玩游戏,发现蓝牙连接手柄没有震动功能,手柄直连电脑是可以震动功能的,玩地平线时试过那个手柄震动功能之后,就再也回不去了,于是想找个便宜的方案曲线救国,海鲜市场50块钱淘了这个小主机,x86/64构架,只有2g内存和4g硬盘,可玩性不高,但是cpu跟j1900差不多,usb口也很丰富,4个USB2.0+2个USB3.0接口,完全可以做书房电脑主机的usb延伸,顺便还可以跑点小程序也是没问题的。
image.png

image.png

找了个usb串流软件只能在windows下用,所以我准备装一个windows,但是4G硬盘存储太拉跨,装windows是完全不够用,也考虑过windows to go安装到u盘里,而windows to go对u盘的要求挺高,最便宜的价格都要100多了,已经超出了小主机的价格,完全无法接受,所以想到了用iscsi无盘启动的方式,经过几天的折腾,最终完美启动。

要准备的文件

  • wimboot:用来启动windows pe
  • ipxe:这个要自己编译,因为要嵌入自己的脚本
  • windows镜像
  • u盘:用rufus等工具把windows镜像写入u盘。如果不想用u盘也可以把镜像挂载到群晖共享文件夹,在windowspe里用net use命令挂载镜像所在的文件夹,执行setup.exe启动,这里为了省事直接用了u盘。
    需要的文件可以自己下载编译,也可以用我编译好的版本和镜像,但是注意6111端口号要和我的一样。

(wimboot、编译好的ipxe、windows镜像、我写的ipxe启动脚本)的下载链接:
https://pan.baidu.com/s/1Lb69OU13pGFt-ff78TSGpA?pwd=1234 提取码: 1234
https://url95.ctfile.com/d/44827295-61067476-560716?p=4681 (访问密码: 4681)

0 遇到的坑

0.0 windows的版本

唯一能成功安装的windows版本是windows 1607,在这之前之后的版本都不行,不要问我怎么知道的😭。
本来想讨巧在其他电脑上直接把windows装到iscsi硬盘直接给小主机使用,但是发现用DISM命令直接从windows镜像提取文件再写入iscsi硬盘的方式在网启的时候会报错( inaccessible boot device)。
后来直接用U盘安装发现错误一样,最终确定是镜像的问题,下次折腾再试试DISM命令直接写入ISCSI硬盘。

0.1 群晖的iscsi格式

我在群晖部署的iscsi硬盘是一个target映射一个lun:

1
sanboot iscsi:192.168.1.225::::iqn.2000-01.com.synology:diskstation.Target-win10

这种死活连接不上,这种::::冒号之间不填都是默认值,第三个冒号后面是LUN的编号,看网上的文章在使用sanboot命令时都是用的默认值,但是经过我的试验使用把LUN的编号改成1才启动成功

1
sanboot iscsi:192.168.1.225:::1:iqn.2000-01.com.synology:diskstation.Target-win10

这里第三个冒号后面的是LUN ID,如果不填默认是0,看来群晖的LUN映射编号是从1开始的。

0.2 群晖iscsi初次登录的权限问题

如果群晖的iscsi target设置了权限的话,在第一次执行sanboot时会连接失败(can not open SAN device),这个要在群晖SAN管理器中的iscsi target页面等待小主机执行sanboot,执行sanboot后在群晖的san manager的iscsi页面会看到连接过来的客户端IP,这个时候点括号里的create new host,然后给这个客户端设置LUN的可读写权限,再次重启小主机进行引导就能连接成功了。
image.png

0.3 ipxe的编译

如果使用我编译好的ipxe就不用看了,要自己编译的话,首先要开个ubuntu虚拟机或者ubuntu docker环境来编译,在macos、windows下是编译不了的,或者说要配置复杂的交叉编译命令,最好还是开个虚拟机方便一点。关于编译命令,官网上说的编译依赖有点过时,经过试验我安装了如下依赖:

1
2
3
4
5
6
7
8
sudo apt install git  
sudo apt install git-core   #不装这个编译时会出现文件找不到
sudo apt install liblzma-dev #不装会出现lzma.h错误
sudo apt install gcc
sudo apt install make
sudo apt install mtools  #DOS命令模拟器
sudo apt install mkisofs #不生成ISO不需要
sudo apt install syslinux #不生成ISO不需要

在src目录下建立一个链式脚本chain.ipxe,内容如下:

1
2
3
#!ipxe
dhcp
chain http://${next-server}:6111/boot.ipxe

${next-server}:6111是我在群晖webstation上放的更完整的引导脚本,${next-server}变量是dhcp服务器返回的下一个服务器的地址,这个在 配置软路由 章节会提到如何设置,现在开始编译:

1
2
3
4
5
cd src
make clean
make bin-x86_64-efi/ipxe.efi EMBED=chain.ipxe
mkdir -p myipxe/64
cp bin-x86_64-efi/ipxe.efi myipxe/64

src/myipxe/64目录下找到ipxe.efi,拷贝到群晖websation的目录下,用浏览器确保http://192.168.1.225:6111/ipxe.efi可以正常访问。

这个时候小主机使用网络引导时就可以使用ipxe执行http://${next-server}:61111/boot.ipxe中的命令了。

0.4 网口问题

这个主机的网卡是realtek 8168,速率是10/100/1000Mbps自适应的,进入系统后网络接口显示的是100Mbps,折腾后发现是网线问题,换了根网线后,协商速率变成1000Mbps了,不过内网librespeed跑了下,最大只能跑满500Mbps左右,只能跑一半的速度,一般来说也够了。
image.png

1 安装步骤

1.0 网络引导流程图

先看完整pxe网络引导流程图:

![[ipxe引导示意图.excalidraw.svg]]

1.0 BIOS选项设置

  • BIOS的密码:zte-ct
  • BIOS启动顺序改为网络优先
  • IDE配置修改为IDE->AHCI,原先是AMDAHCI
  • 启动类型改为uefi启动或者dual boot type
  • pxe boot capability改为uefi:ipv4

ps:如果bios改坏了变砖,可以把机子拆开把电池扣下来放电就还原回去了~

1.1 配置软路由

首先要配置软路由的dhcp服务器,让dhcp服务器告诉网卡tftp服务器的地址和要获取的引导文件名字,我的软路由系统是iStoreOS(基于openwrt),在网络->DHCP/DNS->PXE/TFTP设置,添加ipxe的信息:
image.png

填入群晖的ip地址,名称,和引导固件的文件名:
image.png

填这个的目的是让dhcp服务器告诉网卡下一步到哪里里去下载引导文件。

其他软路由类似,一些硬路由也有这个功能,如果没有的话,替代方案是关闭路由器上的DHCP服务,并打开群晖的DHCP服务,用群晖来实现给内网提供ip地址服务。
注意如果要用群晖的dhcp服务,就必须关闭路由器上的dhcp服务,因为整个内网只能有一个dhcp服务器,如果有多个dhcp服务会造成内网ip地址混乱。

1.2 在群晖上配置tftp服务

如果软路由支持开启tftp服务也可以将引导固件放在软路由上,但是为了方便我将文件都统一存放在群晖上方便管理。

打开群晖页面,在控制面板->文件服务->高级设置->tftp,勾上启用tftp服务,并设置根文件夹:
image.png

然后把ipxe.efi放到/web/tftp目录下(见前面的编译方法)。
前面提到ipxe.efi内嵌了自己写的脚本,脚本中用chain命令链式启动了一个新的脚本:

1
chain http://${next-server}:6111/boot.ipxe

为什么要这样做呢?因为将引导脚本内嵌到ipxe.efi中的,不方便修改,所以内嵌脚本中直接链式启动一个新的脚本灵活一点。另外前面有提到我发现ipxe.efi启动时似乎会隐式执行autoexec.ipxe脚本,但是我在官网上没有找到使用说明,就没继续折腾了,后面的朋友可以试试这个方法,如果行得通可以省去ipxe.efi的编译过程,直接使用官网release原版。

1.3 在群晖web station服务上建立一个http服务,端口号设置为脚本里的6111

群晖上打开Web Station->网页服务,选择本机脚本语言网站:
image.png

名称描述随便填,目录选择web/www,自己要在相应位置创建目录:
image.png

image.png

然后在网络门户新增一个门户:
image.png
在web/www/目录下随便放个文件用http协议访问下,能读取到就没问题了。

1.4 制作windows pe(windows预执行环境)

这一步的目的是为了能进入windows安装程序的命令行界面启动U盘上的windows镜像,但不是真的要使用这些文件来安装windows。所以我做了个最简单的windows pe。
挂载windows镜像,把以下文件按对应目录的方式拷贝到群晖的6111端口的web服务根目录中:

1
2
3
boot/bcd
boot/bcd.sdi
sources/boot.wim

在把前面下载的wimboot也放到目录中,最终web服务根目录如下:

1
2
3
4
wimboot
boot/bcd
boot/bcd.sdi
sources/boot.wim

到这里一个最最最简单的可以用ipxe启动的pe预安装环境就配置好了。

1.5 boot.ipxe启动脚本

我从网上找了些脚本,做了修改,只实现了两个功能,从iscsi磁盘引导,和进入前面制作好的windows pe环境,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!ipxe
#下面这个3000是菜单等待时间代表3秒,
set menu-timeout 3000
set menu-default WINDOWS
isset ${ip} || dhcp
set initiator-iqn iqn.${product}:${mac:hexhyp}

:start
menu iPXE Boot Menu
item --gap -- --------------------------------- WIN --------------------------------
item WINDOWS BOOT WINDOWS(ISCSI)
item --gap -- ---------------------------- Advanced options ------------------------
item --key p pe PE system -- p
item --key s shell shell -- s
item --key r reboot reboot computer -- r
item --key x exit Exit iPXE and continue BIOS boot -- x
item --gap --
item --gap -- ------------------------------- systeminfo ---------------------------
item --gap -- DHCP Server: ${dhcp-server}
item --gap -- IP: ${ip}
item --gap -- MAC: ${mac}
item --gap -- netmask: ${netmask}
item --gap -- Gateway: ${gateway}
item --gap -- DNS: ${dns}
item --gap -- UUID: ${uuid}
item --gap -- initiator-iqn: ${initiator-iqn}
choose --timeout ${menu-timeout} --default ${menu-default} selected
goto ${selected}

:reboot
reboot

:exit
exit

:shell
shell
goto start


:WINDOWS
chain /mac/${mac:hexhyp} || goto install

:pe
sanhook iscsi:${next-server}:::1:iqn.2000-01.com.synology:diskstation.Target-win10 || goto shell
kernel wimboot
initrd http://${next-server}:6111/boot/bcd BCD
initrd http://${next-server}:6111/boot/boot.sdi boot.sdi
initrd http://${next-server}:6111/sources/boot.wim boot.wim
boot

把boot.ipxe放到web根目录下,然后就小主机就可以开机了。

1.6 安装windows

先把安装u盘插到usb口,开机后最终会执行boot.ipxe,就可以看到一个菜单项,第一次要选择第二项:PE System菜单
进入pe环境,注意这个pe环境不像网上的windows pe系统那么完整,它本质上只能进入windows安装界面的第一步,如果真的点install会失败(因为文件不全),我只是用它来进入命令行界面(选择repair computer->trouble shooting,找到命令行选项):
image.png

把前面提到的windows镜像用rufus写到u盘里后插入u盘,在命令行中用dir的方式切换到u盘的目录,dir c:,dir d:这样一个一个的试,然后cd /d c:\ 切换过去,执行setup.exe就可以直接启动u盘上的安装程序了。

1.7 直接启动iscsi磁盘上的windows

我的boot.ipxe脚本启动windows是按照mac地址来启动不同的iscsi磁盘,
要在web根目录下的创建一个文件/mac/xx-xx-xx-xx-xx-xx这也是一个引导脚本,内容如下:

1
2
3
4
#!ipxe
set keep-san 1
sanboot iscsi:${next-server}:::1:iqn.2000-01.com.synology:diskstation.Target-win10
boot

我是为了方便一个脚本引导多台主机这样写的,如果不需要网络引导多台电脑的话,可以把这几行代码直接写到boot.ipxe中,修改如下:

1
2
3
4
:WINDOWS 
set keep-san 1
sanboot iscsi:${next-server}:::1:iqn.2000-01.com.synology:diskstation.Target-win10
boot

到这里,启动的时候选择BOOT WINDOWS(ISCSI)菜单,就可以直接进入windows界面了。

最终效果图

刚安装完成时CPU几乎满载,原版windows装好后会运行一堆有得没得的程序,等一段时间后自然会降下来,最好还是找几个windows优化工具关闭一些不需要的服务。
image.png

装好后马上关闭系统的虚拟内存,因为如果通过无盘启动windows的话,虚拟内存的页面文件是建立群晖iscsi硬盘上的,多多少少会影响运行速度。
image.png

这小主机能装windows,50块钱的价格就值回来了,你也可以装个linux跑点小服务啥的,其他玩法大家就自由发挥了~

更多内容请关注我的博客