4. HTTP 服务器搭建:让 PXE 客户端能“下载”到文件

上一章我们聊了 DHCP 和 TFTP,它们解决了“找服务器”和“下载小文件”的问题。但 PXE 真正要加载的内核、initrd 文件系统,甚至整个 ISO 镜像,动辄几百兆。TFTP 那点传输效率,说实话,慢得让人抓狂。

这时候,HTTP 就该登场了。说白了,HTTP 在 PXE 里的角色就是一个“高效文件搬运工”。它速度快、支持大文件、还能做并发传输。我个人习惯,只要不是古董级网络环境,一律优先用 HTTP 替代 TFTP 来传内核和根文件系统。

核心认知: PXE 客户端从 DHCP 拿到 IP 和启动文件路径后,会先通过 TFTP 下载 pxelinux.0 和配置文件。配置文件里指定的内核、initrd 路径,如果以 http:// 开头,客户端就会自动改用 HTTP 协议去拉取。这就是 HTTP 在 PXE 中的关键作用。

4.1 为什么 PXE 需要 HTTP?

你想想看,传统 PXE 只用 TFTP,但 TFTP 是基于 UDP 的,没有窗口滑动机制,每次只能传 512 字节,还要等确认。传一个 5MB 的内核还行,要是传一个 200MB 的 initrd,那等待时间简直让人崩溃。

我在项目中遇到过最极端的情况:一个教育城域网批量部署 500 台终端,用 TFTP 传 300MB 的镜像,平均每台要等 8 分钟。换成 HTTP 后,同样的文件,1 分半钟就搞定了。这就是差距。

HTTP 在 PXE 中的优势非常明显:

  • 传输效率高: 基于 TCP,有拥塞控制和窗口滑动,大文件传输速度远超 TFTP。
  • 支持断点续传: 虽然 PXE 客户端本身不常用这个特性,但 HTTP 协议本身支持。
  • 并发能力强: 一台 HTTP 服务器可以同时服务上百个 PXE 客户端,而 TFTP 的并发能力很弱。
  • 配置灵活: 可以通过虚拟主机、目录映射等方式,轻松管理不同版本的启动文件。
我的建议: 在实际生产环境中,我通常让 TFTP 只负责传输 pxelinux.0 和轻量级的配置文件(几百 KB),而把内核、initrd、甚至整个 squashfs 文件系统都交给 HTTP 来承载。这样既保证了兼容性,又提升了整体部署速度。

4.2 安装与配置 Nginx 作为 PXE 的 HTTP 服务器

Nginx 是我个人最推荐的 PXE HTTP 服务器。为什么?因为它轻量、高并发、配置简单。你不需要装一堆模块,一个核心配置就能跑起来。

下面我以 CentOS/RHEL 7/8 为例,带你走一遍完整的安装配置流程。

4.2.1 安装 Nginx

# 安装 EPEL 源(如果还没装)
yum install -y epel-release

# 安装 Nginx
yum install -y nginx

# 启动并设置开机自启
systemctl start nginx
systemctl enable nginx

# 检查状态
systemctl status nginx

安装完成后,默认的网站根目录在 /usr/share/nginx/html。但我们要做 PXE 服务,一般会单独建一个目录来存放启动文件。

4.2.2 配置 PXE 专用的虚拟主机

我个人习惯为 PXE 服务单独建一个虚拟主机配置,这样方便管理和隔离。

# 创建 PXE 文件存放目录
mkdir -p /data/pxe/centos7
mkdir -p /data/pxe/centos8

# 创建 Nginx 配置文件
vim /etc/nginx/conf.d/pxe.conf

写入以下配置:

server {
    listen       80;
    server_name  pxe.example.com;  # 换成你的实际域名或 IP

    # 关闭 access_log 可以减轻磁盘 IO 压力,生产环境建议开启
    access_log  /var/log/nginx/pxe_access.log main;
    error_log   /var/log/nginx/pxe_error.log;

    # 根目录指向 PXE 文件总目录
    root /data/pxe;

    # 开启目录列表,方便调试时查看文件
    autoindex on;
    autoindex_exact_size off;
    autoindex_localtime on;

    # 针对特定文件类型的优化
    location ~* \.(iso|img|vmlinuz|initrd|squashfs)$ {
        # 大文件优化:启用 sendfile 和 tcp_nopush
        sendfile       on;
        tcp_nopush     on;
        # 设置缓存过期时间,避免浏览器缓存(PXE 客户端一般不会缓存)
        expires        off;
    }

    # 禁止访问隐藏文件
    location ~ /\. {
        deny all;
    }
}
注意: 配置中的 autoindex on 在调试阶段非常有用。我曾经有一次排查问题,发现客户端报 404,打开目录列表一看,原来是文件名大小写写错了。这个开关能帮你快速定位文件路径问题。但生产环境建议关闭,避免暴露目录结构。

配置完成后,检查语法并重载:

nginx -t
systemctl reload nginx

4.2.3 目录映射与文件放置

现在我们把 PXE 启动文件放到对应目录下。假设我们要部署 CentOS 7 和 CentOS 8:

# 挂载 ISO 镜像并复制内核和 initrd
mount -o loop /path/to/CentOS-7-x86_64-Minimal-2009.iso /mnt
cp /mnt/images/pxeboot/vmlinuz /data/pxe/centos7/
cp /mnt/images/pxeboot/initrd.img /data/pxe/centos7/

# 同样处理 CentOS 8
mount -o loop /path/to/CentOS-8.5.2111-x86_64-dvd1.iso /mnt
cp /mnt/images/pxeboot/vmlinuz /data/pxe/centos8/
cp /mnt/images/pxeboot/initrd.img /data/pxe/centos8/

# 别忘了复制整个 ISO 或者 squashfs 文件系统(如果需要网络安装)
cp /path/to/CentOS-7-x86_64-Minimal-2009.iso /data/pxe/centos7/

最终目录结构应该是这样的:

/data/pxe/
├── centos7/
│   ├── vmlinuz
│   ├── initrd.img
│   └── CentOS-7-x86_64-Minimal-2009.iso
└── centos8/
    ├── vmlinuz
    ├── initrd.img
    └── CentOS-8.5.2111-x86_64-dvd1.iso

4.3 安装与配置 Apache(备选方案)

虽然我推荐 Nginx,但有些老系统或者特定场景下,Apache 可能更合适。比如你需要在同一个服务器上同时跑 PHP 应用和 PXE 服务,Apache 的模块生态更丰富。

配置 Apache 也很简单:

# 安装 Apache
yum install -y httpd

# 创建 PXE 目录
mkdir -p /var/www/html/pxe

# 配置虚拟主机(在 /etc/httpd/conf.d/pxe.conf)
<VirtualHost *:80>
    ServerName pxe.example.com
    DocumentRoot /var/www/html/pxe

    <Directory /var/www/html/pxe>
        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>
</VirtualHost>

# 启动服务
systemctl start httpd
systemctl enable httpd

Apache 和 Nginx 的核心区别在于:

对比项 Nginx Apache
并发模型 事件驱动,异步非阻塞 进程/线程模型,每个连接一个进程
静态文件性能 极高,尤其适合大文件 良好,但高并发下资源消耗更大
配置复杂度 简洁,学习曲线平缓 较复杂,.htaccess 机制灵活但影响性能
内存占用 低,适合嵌入式或低配服务器 相对较高
动态内容支持 需配合 FastCGI 原生支持模块加载
我的选择: 如果是纯 PXE 文件分发场景,无脑选 Nginx。如果服务器上还要跑其他 Web 应用,比如 PXE 配置管理后台,那 Apache 可能更顺手。但说实话,我现在大部分项目都是 Nginx + PHP-FPM 的组合,既能扛 PXE 大文件,又能跑动态页面。

4.4 静态资源访问测试

服务器配好了,文件也放上去了。怎么验证能不能正常访问?我一般分三步走。

4.4.1 本地 curl 测试

在服务器本机先测一下:

# 测试根目录是否可访问
curl -I http://localhost/

# 测试具体文件是否可访问
curl -I http://localhost/centos7/vmlinuz

# 查看返回的 HTTP 头,重点关注 200 OK 和 Content-Length
HTTP/1.1 200 OK
Server: nginx/1.20.1
Content-Type: application/octet-stream
Content-Length: 6520832
Last-Modified: Tue, 15 Dec 2020 08:30:00 GMT

如果返回 200,说明文件可以正常访问。如果返回 403,检查目录权限;如果返回 404,检查文件路径是否正确。

4.4.2 远程客户端测试

在另一台机器上,用 wget 或 curl 测试:

# 从客户端下载测试
wget http://192.168.1.100/centos7/vmlinuz

# 或者用 curl 测试
curl -O http://192.168.1.100/centos7/initrd.img

这里要注意防火墙。我曾经在客户现场排查了半天,最后发现是 firewalld 没放行 80 端口:

# 放行 HTTP 服务
firewall-cmd --permanent --add-service=http
firewall-cmd --reload

4.4.3 结合 PXE 配置文件验证

最后一步,修改 PXE 的默认配置文件,把内核和 initrd 的路径改成 HTTP 协议:

# 在 pxelinux.cfg/default 中
LABEL linux
    MENU LABEL Install CentOS 7 via HTTP
    KERNEL http://192.168.1.100/centos7/vmlinuz
    APPEND initrd=http://192.168.1.100/centos7/initrd.img inst.repo=http://192.168.1.100/centos7/

然后启动一台 PXE 客户端,观察启动过程。如果能看到内核加载、initrd 解压,并且进入安装界面,说明 HTTP 服务器配置成功了。

避坑指南: 我曾经遇到过一个问题:客户端能下载 vmlinuz,但加载 initrd 时报错“Out of memory”。排查了半天,发现是 initrd 文件太大(超过 500MB),而客户端的 PXE 栈内存有限。解决方案是把 initrd 拆分成多个小文件,或者改用 dracut 生成更精简的 initrd。所以,如果你的 initrd 超过 300MB,建议检查一下客户端固件的内存限制。

4.5 本章知识体系总览

下面这张图,帮你把 HTTP 服务器在 PXE 中的位置和配置要点串起来:

HTTP 服务器在 PXE 中的角色与配置流程 DHCP 服务器 TFTP 服务器 HTTP 服务器 Nginx / Apache PXE 文件存储 vmlinuz / initrd ISO / squashfs 安装 Web 服务器 配置虚拟主机 目录映射与权限 防火墙放行 核心流程 1. DHCP 分配 IP 和启动文件路径 2. TFTP 下载 pxelinux.0 和配置 3. HTTP 下载内核和根文件系统

这张图清晰地展示了:DHCP 和 TFTP 负责“引导”阶段,而 HTTP 负责“加载”阶段。配置 HTTP 服务器的核心就是安装、建目录、配虚拟主机、放文件、开防火墙,五步走完。