3. 镜像格式与结构

TFTP 这玩意儿,说白了就是网络启动里的“送餐员”。它不搞复杂认证,也不玩加密,就是闷头把文件从服务器搬到客户端。但你别小看它——PXE 启动的第一口饭,全靠它喂。我见过太多启动失败,最后查出来是 TFTP 没搭对。

今天咱们就把 tftp-hpa 这个最常用的实现,从安装到权限控制,掰开揉碎了讲清楚。

3.1 为什么选 tftp-hpa?

Linux 下 TFTP 服务器有好几个:tftpd、atftpd、dnsmasq 内置的 TFTP 模块……但我个人习惯用 tftp-hpa。为什么?

  • 轻量:二进制包才几百 KB,不依赖一堆库。
  • 稳定:H. Peter Anvin 维护的,跟 syslinux、pxelinux 是同一拨人出品,兼容性最好。
  • 安全:默认 chroot 到根目录,客户端看不到外面的世界。
我的经验: 早期我试过 atftpd,结果传大文件时偶尔丢包。换成 tftp-hpa 后,再没出过幺蛾子。如果你在生产环境做 PXE,直接选 tftp-hpa 就对了。

3.2 安装 tftp-hpa

不同发行版包名略有差异,但核心就两个组件:服务器端(tftpd-hpa)和客户端(tftp-hpa)。客户端用来调试,建议一起装。

Debian / Ubuntu 系

apt update
apt install tftpd-hpa tftp-hpa -y

RHEL / CentOS / Rocky 系

yum install tftp-server tftp -y
# 或者用 dnf
dnf install tftp-server tftp -y

装完后,检查一下服务状态:

systemctl status tftpd-hpa   # Debian 系
systemctl status tftp.socket  # RHEL 系

嗯,这里要注意:RHEL 系默认走 systemd socket 激活,服务不会常驻,有请求才启动。Debian 系则是独立服务,一直跑着。

3.3 根目录结构:TFTP 的“文件仓库”

TFTP 服务器需要一个根目录,所有客户端能访问的文件都放在这里。默认路径是 /srv/tftp(Debian)或 /var/lib/tftpboot(RHEL)。

我个人习惯统一用 /srv/tftp,好记。目录结构长这样:

/srv/tftp/
├── pxelinux.0          # PXE 引导程序
├── ldlinux.c32         # syslinux 库文件
├── menu.c32            # 菜单模块
├── chain.c32           # 链式加载模块
├── pxelinux.cfg/       # PXE 配置文件目录
│   ├── default         # 默认配置
│   └── 01-aa-bb-cc-dd-ee-ff  # 按 MAC 地址的配置
├── images/             # 内核和 initrd
│   ├── vmlinuz-5.10.0
│   └── initrd.img-5.10.0
├── efi/                # UEFI 启动文件
│   ├── bootx64.efi
│   └── grubx64.efi
└── iso/                # 可选的 ISO 文件
    └── netboot.iso
核心原则: TFTP 根目录下的路径,就是客户端请求的路径。比如客户端请求 pxelinux.cfg/default,实际对应 /srv/tftp/pxelinux.cfg/default。不要搞错相对路径和绝对路径。

3.4 传输模式:octet 与 netascii

TFTP 支持两种传输模式:

模式 说明 适用场景
netascii 文本模式,会做换行符转换(LF ↔ CRLF) 纯文本配置文件(极少用)
octet 二进制模式,原样传输,不做任何转换 内核、initrd、引导程序、ISO 文件

说白了,网络启动里 99% 的情况都用 octet 模式。你想想看,vmlinuz 是二进制文件,如果 netascii 给你把 0x0A 换成 0x0D 0x0A,内核直接就崩了。

我曾经踩过的坑: 有一次用 TFTP 传一个压缩的 initrd,客户端一直报 CRC 错误。查了半天,发现 TFTP 客户端默认用了 netascii 模式。改成 octet 后,问题立刻消失。所以,所有网络启动文件必须用 octet 模式传输。

3.5 权限控制:别让 TFTP 成为后门

TFTP 没有用户认证,谁都能读文件。所以权限控制全靠文件系统权限和 chroot 机制。

3.5.1 文件权限

TFTP 服务器通常以 tftp 用户运行。根目录和内部文件必须让这个用户可读:

chown -R tftp:tftp /srv/tftp
chmod -R 755 /srv/tftp

注意:不要给写权限。除非你明确需要客户端上传文件(比如网络备份场景),否则写权限就是安全隐患。

3.5.2 chroot 隔离

tftp-hpa 默认启用 chroot。客户端看到的根目录就是 /srv/tftp,它无法访问 /etc/passwd、/var/log 等系统文件。配置在 /etc/default/tftpd-hpa(Debian)或 /etc/xinetd.d/tftp(RHEL)里:

# Debian /etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure --create"

关键参数说明:

  • --secure:启用 chroot,把根目录锁定在 TFTP_DIRECTORY。
  • --create:允许客户端创建文件(上传)。默认不开启,需要时才加。
  • --blocksize 1468:我建议加上这个,能提升大文件传输效率。

3.5.3 防火墙放行

TFTP 使用 UDP 69 端口。别忘了在防火墙里放行:

# ufw
ufw allow 69/udp

# firewalld
firewall-cmd --add-port=69/udp --permanent
firewall-cmd --reload

3.6 核心流程一览

下面这张图总结了 TFTP 服务器搭建的完整逻辑:

TFTP 服务器搭建核心流程 TFTP 服务器搭建核心流程 1. 安装 tftp-hpa 2. 配置根目录结构 3. 设置传输模式 (octet) 4. 权限控制 (chroot + 755) 5. 防火墙放行 UDP 69 提示:每一步都依赖上一步,顺序不要乱。尤其是权限控制,很多人忘了 chroot 导致安全漏洞。

3.7 验证搭建是否成功

装完别急着走,先验证一下。在另一台机器上执行:

tftp 192.168.1.100
tftp> get pxelinux.0
tftp> quit

如果文件能正常下载,说明 TFTP 服务器跑起来了。如果超时或报错,按下面顺序排查:

  1. 防火墙:UDP 69 端口通了吗?
  2. SELinux:RHEL 系记得检查 getenforce,必要时 setenforce 0 测试。
  3. 文件权限:tftp 用户能读根目录下的文件吗?
  4. chroot 路径:配置文件里的目录路径写对了没?
调试小技巧: 在服务器上开一个 tcpdump 抓包:tcpdump -i any port 69 -X。能看到客户端请求了什么文件,服务器返回了什么错误。这招帮我解决过无数疑难杂症。

3.8 小结

TFTP 服务器搭建,说白了就五步:安装、配目录、选模式、控权限、放防火墙。每一步都不难,但漏掉一个就可能让 PXE 启动卡住。我个人建议把根目录结构固定下来,以后所有项目都用同一套,省心。