> For the complete documentation index, see [llms.txt](https://handbook.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://handbook.bsdcn.org/di-35-zhang-gao-ji-wang-luo/35.10.-shi-yong-pxe-jin-hang-wu-pan-cao-zuo.md).

# 35.10.使用 PXE 进行无盘操作

Intel® 预引导执行环境（PXE）能让操作系统通过网络引导。例如，FreeBSD 系统可以通过网络引导，并使用从 NFS 服务器挂载的文件系统运行，无需本地磁盘。PXE 支持通常在 BIOS 中提供。要在机器引导时使用 PXE，请在 BIOS 设置中选择“从网络引导”选项，或在系统初始化过程中按下功能键。

为提供操作系统通过网络引导所需的文件，PXE 设置还需要正确配置的 DHCP、TFTP 和 NFS 服务器，其中：

* 初始参数，如 IP 地址、可执行引导文件名和位置、服务器名称以及根路径，从 DHCP 服务器获取。
* 操作系统加载器文件通过 TFTP 引导。
* 文件系统通过 NFS 加载。

当计算机通过 PXE 引导时，它会通过 DHCP 获取有关从哪里获取初始引导加载程序文件的信息。主机接收到这些信息后，它通过 TFTP 下载引导加载程序并执行它。在 FreeBSD 中，引导加载程序文件是 **/boot/pxeboot**。当 **/boot/pxeboot** 执行后，FreeBSD 内核将被加载，并且 FreeBSD 的其余引导过程将继续，如 [FreeBSD 引导过程](/di-15-zhang-freebsd-de-yin-dao-guo-cheng/15.1.-gai-shu.md) 中所述。

> **注意**
>
> 对于基于 UEFI 的 PXE 引导，实际使用的引导加载程序文件是 **/boot/loader.efi**。请参阅下文的 [调试 PXE 问题](#diao-shi-pxe-wen-ti) 部分，了解如何使用 **/boot/loader.efi**。

本节介绍如何在 FreeBSD 系统上配置这些服务，以便其他系统可以通过 PXE 引导到 FreeBSD。有关更多信息，请参考 [diskless(8)](https://man.freebsd.org/cgi/man.cgi?query=diskless\&sektion=8\&format=html)。

> **当心**
>
> 如前所述，提供这些服务的系统不够安全。应当将其置于网络中的受保护区域，且不应被其他主机信任。

## 35.10.1. 配置 PXE 环境

本节中的步骤配置了内置的 NFS 和 TFTP 服务器。下一节将演示如何安装和配置 DHCP 服务器。在此示例中，包含 PXE 用户使用的文件的目录为 **/b/tftpboot/FreeBSD/install**。确保该目录存在，并且在 **/etc/inetd.conf** 和 **/usr/local/etc/dhcpd.conf** 中设置相同的目录名称非常重要。

> **注意**
>
> 以下命令示例假设使用 [sh(1)](https://man.freebsd.org/cgi/man.cgi?query=sh\&sektion=1\&format=html) shell。使用 [csh(1)](https://man.freebsd.org/cgi/man.cgi?query=csh\&sektion=1\&format=html) 和 [tcsh(1)](https://man.freebsd.org/cgi/man.cgi?query=tcsh\&sektion=1\&format=html) 的用户需要启动一个 [sh(1)](https://man.freebsd.org/cgi/man.cgi?query=sh\&sektion=1\&format=html) shell 或将命令改为 [csh(1)](https://man.freebsd.org/cgi/man.cgi?query=csh\&sektion=1\&format=html) 语法。

1. 创建根目录，该目录将包含一个可以通过 NFS 挂载的 FreeBSD 安装：

   ```sh
   # export NFSROOTDIR=/b/tftpboot/FreeBSD/install
   # mkdir -p ${NFSROOTDIR}
   ```
2. 通过向 **/etc/rc.conf** 添加以下行来启用 NFS 服务器：

   ```sh
   nfs_server_enable="YES"
   ```
3. 通过向 **/etc/exports** 添加以下内容来通过 NFS 导出无盘根目录：

   ```sh
   /b -ro -alldirs -maproot=root
   ```
4. 启动 NFS 服务器：

   ```sh
   # service nfsd start
   ```
5. 通过向 **/etc/rc.conf** 添加以下行来启用 [inetd(8)](https://man.freebsd.org/cgi/man.cgi?query=inetd\&sektion=8\&format=html)：

   ```sh
   inetd_enable="YES"
   ```
6. 取消注释 **/etc/inetd.conf** 中的以下行，确保它前面没有 `#` 符号：

   ```sh
   tftp dgram udp wait root /usr/libexec/tftpd tftpd blocksize 1468 -l -s /b/tftpboot
   ```

> **注意**
>
> 指定的 tftp 块大小（例如 1468 字节）替换了默认的 512 字节大小。有些 PXE 版本需要使用 TCP 版本的 TFTP。在这种情况下，取消注释第二个 `tftp` 行，其中包含 `stream tcp`。

7. 启动 [inetd(8)](https://man.freebsd.org/cgi/man.cgi?query=inetd\&sektion=8\&format=html)：

   ```sh
   # service inetd start
   ```
8. 将基本系统安装到 **${NFSROOTDIR}** 中，可以通过解压官方归档文件或重新构建 FreeBSD 内核和用户空间来完成（有关更详细的说明，请参考 [“从源代码更新 FreeBSD”](/di-27-zhang-freebsd-geng-xin-yu-sheng-ji/27.6.-cong-yuan-dai-ma-geng-xin-freebsd.md)，但在运行 `make installkernel` 和 `make installworld` 命令时不要忘记添加 `DESTDIR=${NFSROOTDIR}`）。
9. 测试 TFTP 服务器是否正常工作，并能通过 PXE 获取引导加载程序：

   ```sh
   # tftp localhost
   tftp> get FreeBSD/install/boot/pxeboot
   Received 264951 bytes in 0.1 seconds
   ```
10. 编辑 **${NFSROOTDIR}/etc/fstab**，并创建一个条目以通过 NFS 挂载根文件系统：

```sh
# Device                                         Mountpoint    FSType   Options  Dump Pass
myhost.example.com:/b/tftpboot/FreeBSD/install       /         nfs      ro        0    0
```

将 *myhost.example.com* 替换为 NFS 服务器的主机名或 IP 地址。在此示例中，根文件系统以只读方式挂载，以防止 NFS 客户端可能删除根文件系统的内容。

11. 为 PXE 引导的客户端机器设置根密码：

```sh
# chroot ${NFSROOTDIR}
# passwd
```

12. 如果需要，通过编辑 **${NFSROOTDIR}/etc/ssh/sshd\_config** 文件并启用 `PermitRootLogin`，为 PXE 引导的客户端机器启用 [ssh(1)](https://man.freebsd.org/cgi/man.cgi?query=ssh\&sektion=1\&format=html) 根登录。该选项在 [sshd\_config(5)](https://man.freebsd.org/cgi/man.cgi?query=sshd_config\&sektion=5\&format=html) 中有详细说明。
13. 在 **${NFSROOTDIR}** 中执行任何其他所需的自定义操作。这些自定义操作可能包括安装软件包或使用 [vipw(8)](https://man.freebsd.org/cgi/man.cgi?query=vipw\&sektion=8\&format=html) 编辑密码文件。

当从 NFS 根卷引导时，**/etc/rc** 检测到 NFS 引导并运行 **/etc/rc.initdiskless**。在这种情况下，**/etc** 和 **/var** 必须是内存支持的文件系统，以便这些目录可以写入，而 NFS 根目录保持只读：

```sh
# chroot ${NFSROOTDIR}
# mkdir -p conf/base
# tar -c -v -f conf/base/etc.cpio.gz --format cpio --gzip etc
# tar -c -v -f conf/base/var.cpio.gz --format cpio --gzip var
```

当系统引导时，将创建并挂载 **/etc** 和 **/var** 的内存文件系统，并将 `cpio.gz` 文件的内容复制到其中。默认情况下，这些文件系统的最大容量为 5 兆字节。如果归档文件无法容纳，通常是 **/var** 安装了二进制包，则可以通过在 **${NFSROOTDIR}/conf/base/etc/md\_size** 和 **${NFSROOTDIR}/conf/base/var/md\_size** 文件中输入所需的 512 字节扇区数量（例如，5 兆字节是 10240 扇区）来请求更大的大小。

## 35.10.2. 配置 DHCP 服务器

DHCP 服务器不必与 TFTP 和 NFS 服务器在同一台机器上，但它需要在网络中可访问。

DHCP 并不是 FreeBSD 基本系统的一部分，但可以通过 [net/isc-dhcp44-server](https://cgit.freebsd.org/ports/tree/net/isc-dhcp44-server/) Port 或软件包安装。

安装完成后，编辑配置文件 **/usr/local/etc/dhcpd.conf**。配置 `next-server`、`filename` 和 `root-path` 设置，如下所示：

```sh
subnet 192.168.0.0 netmask 255.255.255.0 {
   range 192.168.0.2 192.168.0.3 ;
   option subnet-mask 255.255.255.0 ;
   option routers 192.168.0.1 ;
   option broadcast-address 192.168.0.255 ;
   option domain-name-servers 192.168.35.35, 192.168.35.36 ;
   option domain-name "example.com";

   # TFTP 服务器的 IP 地址
   next-server 192.168.0.1 ;

   # 通过 tftp 获取的引导加载程序路径
   filename "FreeBSD/install/boot/pxeboot" ;

   # pxeboot 引导加载程序将尝试通过 NFS 挂载该目录作为根文件系统
   option root-path "192.168.0.1:/b/tftpboot/FreeBSD/install/" ;

}
```

`next-server` 指令用于指定 TFTP 服务器的 IP 地址。

`filename` 指令定义了 **/boot/pxeboot** 的路径。使用相对文件名，这意味着路径中不包括 **/b/tftpboot**。

`root-path` 选项定义了 NFS 根文件系统的路径。

编辑完成后，通过向 **/etc/rc.conf** 添加以下行来启用 DHCP 引导：

```sh
dhcpd_enable="YES"
```

然后启动 DHCP 服务：

```sh
# service isc-dhcpd start
```

## 35.10.3. 调试 PXE 问题

配置并启动所有服务后，PXE 客户端应该能通过网络自动加载 FreeBSD。如果某个特定客户端无法连接，在该客户端机器引导时，进入 BIOS 配置菜单并确认其设置为从网络引导。

本节说明了一些调试提示，用于在没有客户端能 PXE 引导时，隔离配置问题的源头。

1. 使用软件包或 Port [net/wireshark](https://cgit.freebsd.org/ports/tree/net/wireshark/) 来调试 PXE 引导过程中的网络流量，过程如下面的图示所示。 ![使用 NFS 根挂载的 PXE 引导过程](https://docs.freebsd.org/images/books/handbook/advanced-networking/pxe-nfs.png)

   图 1. 使用 NFS 根挂载的 PXE 引导过程

   1. 客户端广播 DHCPDISCOVER 消息。
   2. DHCP 服务器响应，返回 IP 地址、`next-server`、`filename` 和 `root-path` 值。
   3. 客户端向 `next-server` 发送 TFTP 请求，请求获取 `filename`。
   4. TFTP 服务器响应并将 `filename` 发送给客户端。
   5. 客户端执行 `filename`，即 [pxeboot(8)](https://man.freebsd.org/cgi/man.cgi?query=pxeboot\&sektion=8\&format=html)，然后加载内核。当内核执行时，指定的 `root-path` 所述的根文件系统通过 NFS 挂载。
2. 在 TFTP 服务器上，查看 **/var/log/xferlog**，确保 `pxeboot` 是从正确的位置获取的。测试此示例配置：

   ```sh
   # tftp 192.168.0.1
   tftp> get FreeBSD/install/boot/pxeboot
   Received 264951 bytes in 0.1 seconds
   ```

   [tftpd(8)](https://man.freebsd.org/cgi/man.cgi?query=tftpd\&sektion=8\&format=html) 和 [tftp(1)](https://man.freebsd.org/cgi/man.cgi?query=tftp\&sektion=1\&format=html) 的 `BUGS` 部分记录了一些 TFTP 的局限性。
3. 确保根文件系统可以通过 NFS 挂载。测试此示例配置：

   ```sh
   # mount -t nfs 192.168.0.1:/b/tftpboot/FreeBSD/install /mnt
   ```
4. 对于基于 UEFI 的 PXE 引导，使用 **boot/loader.efi** 文件替换 **boot/pxeboot** 文件：

   ```sh
   # chroot ${NFSROOTDIR}
   # mv boot/pxeboot boot/pxeboot.original
   # cp boot/loader.efi boot/pxeboot
   ```
