3、TFTP服务器配置:安装与配置tftpd-hpa、文件目录结构、权限设置、传输模式
TFTP 这玩意儿,说白了就是个简化版的 FTP。它没有认证,没有目录浏览,甚至没有可靠的错误恢复机制。那你可能会问:这么简陋的东西,为什么还在用?
嗯,因为它足够简单。在 PXE 网络启动的场景里,客户端(也就是那台还没装系统的裸机)的网卡固件里只烧录了最基本的网络协议栈。你让它跑一个完整的 FTP 或者 HTTP 客户端?不现实。TFTP 的代码量极小,刚好能塞进网卡的 Option ROM 里。所以,它成了网络启动中传输内核和 initrd 的默认选择。
3.1 安装 tftpd-hpa
我个人的习惯是,在 Ubuntu/Debian 系系统上,直接用 apt 搞定。tftpd-hpa 是目前最主流的 TFTP 服务器实现,由 H. Peter Anvin 维护——对,就是那个搞 SYSLINUX 的大神。
sudo apt update
sudo apt install tftpd-hpa -y
安装完成后,服务默认是启动的。你可以检查一下状态:
sudo systemctl status tftpd-hpa
如果看到 active (running),说明已经跑起来了。不过别急,默认配置不一定适合你的网络环境,我们得调一调。
tftp-server,配合 xinetd 管理。但我更推荐 tftpd-hpa,配置更直观,性能也更好。
3.2 配置文件详解
tftpd-hpa 的主配置文件在 /etc/default/tftpd-hpa。打开它,你会看到类似这样的内容:
# /etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure --create"
我来逐行解释一下这些参数,顺便聊聊我在项目中踩过的坑。
| 参数 | 说明 | 我的建议 |
|---|---|---|
TFTP_USERNAME |
运行服务的系统用户 | 保持默认 tftp,不要用 root |
TFTP_DIRECTORY |
TFTP 根目录 | 我习惯用 /srv/tftp,清晰明了 |
TFTP_ADDRESS |
监听地址和端口 | 0.0.0.0:69 表示监听所有网卡 |
TFTP_OPTIONS |
启动选项 | --secure 必须加,--create 按需 |
--secure 这个选项特别重要。它限制了客户端只能访问 TFTP 根目录以内的文件,不能通过 ../ 跳出去。我曾经见过有人没加这个选项,结果客户端直接下载了 /etc/shadow……嗯,那场面相当尴尬。
--create 选项允许客户端上传文件时自动创建新文件。如果你的 PXE 环境只需要下载(比如传输内核和 initrd),可以不加这个选项,更安全。
3.3 文件目录结构
目录结构的设计,直接影响到后续维护的便利性。我推荐这样组织:
/srv/tftp/
├── pxelinux.0 # PXE 引导程序
├── ldlinux.c32 # SYSLINUX 库文件
├── vesamenu.c32 # 图形菜单模块
├── chain.c32 # 链式加载模块
├── memdisk # 内存磁盘工具
├── pxelinux.cfg/ # PXE 配置文件目录
│ ├── default # 默认配置文件
│ └── 01-aa-bb-cc-dd-ee-ff # 按 MAC 地址的配置
├── images/ # 系统镜像目录
│ ├── ubuntu-22.04/ # 按发行版/版本组织
│ │ ├── vmlinuz # 内核
│ │ └── initrd.img # 初始 RAM 磁盘
│ └── centos-9/
│ ├── vmlinuz
│ └── initrd.img
└── iso/ # ISO 镜像文件(可选)
└── netboot.iso
为什么这么分?
- pxelinux.cfg/ 目录放 PXE 的配置文件,PXE 客户端会根据自己的 MAC 地址或 IP 地址来匹配对应的配置文件。匹配不到就用
default。 - images/ 目录按发行版和版本号组织,方便后期维护多个系统版本。我在一次项目中同时维护了 Ubuntu 20.04、22.04 和 CentOS 7、8,这种结构让我少掉了不少头发。
- iso/ 目录是可选的,如果你需要通过网络启动 ISO 文件,可以放在这里。
vmlinuz(全小写),但有些发行版可能用 vmlinuz-5.15.0。请确保你的配置文件和实际文件名完全一致。
3.4 权限设置
权限问题,是 TFTP 服务器配置中最容易出错的环节。我见过太多人花了一下午调试,最后发现只是文件权限没设对。
基本原则:TFTP 服务以 tftp 用户运行,所以 tftp 用户必须对 TFTP 根目录及其下的文件有读取权限。如果开启了上传功能,还需要写入权限。
设置权限的步骤:
- 修改目录所有者:
sudo chown -R tftp:tftp /srv/tftp
- 设置目录权限:
sudo find /srv/tftp -type d -exec chmod 755 {} \;
sudo find /srv/tftp -type f -exec chmod 644 {} \;
这里解释一下:目录需要 755(rwxr-xr-x),因为 tftp 用户需要进入目录(执行权限)。文件只需要 644(rw-r--r--),只读就够了。
- 如果允许上传,给上传目录加写权限:
sudo mkdir -p /srv/tftp/upload
sudo chmod 755 /srv/tftp/upload
sudo chown tftp:tftp /srv/tftp/upload
注意,上传目录的权限要设为 755 而不是 777。777 意味着任何人都可以写,这在生产环境中是安全隐患。
sudo semanage fcontext -a -t tftpdir_t "/srv/tftp(/.*)?"
sudo restorecon -Rv /srv/tftp
或者直接临时关闭 SELinux 测试(不推荐生产环境使用):
sudo setenforce 0
3.5 传输模式
TFTP 支持三种传输模式:netascii、octet 和 mail。不过在实际使用中,你基本只会用到 octet。
| 模式 | 说明 | 适用场景 |
|---|---|---|
netascii |
文本模式,会做换行符转换 | 传输纯文本配置文件 |
octet |
二进制模式,不做任何转换 | 传输内核、initrd、ISO 等二进制文件 |
mail |
邮件模式,已废弃 | 不要用 |
为什么强调用 octet?因为 PXE 启动过程中传输的文件——pxelinux.0、vmlinuz、initrd.img——全都是二进制文件。如果用 netascii 模式,TFTP 服务器会在传输过程中把 \n 转换成 \r\n,这会导致二进制文件损坏。启动时内核加载到一半就崩溃了,你连错误日志都看不到。
在 tftpd-hpa 中,默认就是 octet 模式。你不需要额外配置。但如果你用命令行客户端测试,记得指定模式:
tftp 192.168.1.100
tftp> mode octet
tftp> get pxelinux.0
tftp> quit
或者用一行命令:
tftp 192.168.1.100 -m octet -c get pxelinux.0
3.6 核心流程一览
说了这么多,我们来画一张图,把 TFTP 服务器在整个 PXE 启动流程中的位置看清楚。
从这张图可以看得很清楚:TFTP 服务器在整个流程中扮演的是文件仓库的角色。DHCP 告诉客户端「你的 TFTP 服务器在 192.168.1.100」,然后客户端就去那里下载引导文件、配置文件,最后下载内核和 initrd。整个过程不需要用户名密码,不需要复杂的协议协商,就是简单的「给我文件」→「拿去」。
嗯,这就是 TFTP 的魅力——简单到极致,但也正因为简单,所以可靠。
3.7 验证配置
配置完了,怎么验证?我一般会在本机用 tftp 命令测试一下:
# 安装客户端工具
sudo apt install tftp-hpa -y
# 测试下载
echo "get pxelinux.0" | tftp 127.0.0.1
# 检查文件是否下载成功
ls -la pxelinux.0
如果文件下载下来了,说明 TFTP 服务器工作正常。如果报错 Transfer timed out,多半是防火墙挡住了 69 端口:
sudo ufw allow 69/udp
如果报错 File not found,检查文件路径和权限。记住,TFTP 的路径是相对于 TFTP_DIRECTORY 的。比如你要下载 /srv/tftp/pxelinux.0,在 TFTP 客户端里只需要写 get pxelinux.0。
sudo tcpdump -i any port 69 -nn
这样你能看到客户端发来的请求和服务器返回的响应。如果看到 RRQ(读请求)但没有 DATA 包,说明文件权限或路径有问题。
好了,TFTP 服务器的配置就到这里。记住几个关键点:目录结构要清晰、权限要收紧、传输模式用 octet。把这些搞定了,你的 PXE 启动环境就稳了一半。