内网PXE批量装机实战:DHCP、TFTP与syslinux配置详解 1. 为什么要在内网搭一套 PXE 装机环境很多刚接触服务器运维的朋友会问现在都什么年代了还用得着自己搭 DHCP、TFTP 这套东西吗云厂商一键开机器、镜像市场点两下不就完事了这话对也不对。在公有云上确实轮不到我们操心底层引导可一旦进了企业内网、实验室机房、或者需要批量交付几十上百台物理机的场景PXE 网络引导依然是绕不开的基本功。它解决的核心问题就一个让一台裸机在没有任何本地存储介质的情况下通过网络拿到引导程序、内核和安装源自动完成系统部署。这套东西的价值在于批量和无人值守。你想象一下机房里堆着三十台刚拆箱的服务器一台台插 U 盘装系统光是插拔和等待就能耗掉一整天。而搭好 PXE 之后你只需要改一下 BIOS 的启动顺序剩下的交给网络喝杯咖啡回来机器就装好了。CentOS 8 虽然已经进入维护周期的尾声但大量存量内网环境仍在跑它而且 CentOS 8 在引导链路上和 7 有细微差别尤其是syslinux版本和grub的配合方式踩坑的人不少。这篇文章面向的是有一定 Linux 基础、需要在内网做批量部署的运维人员也适合想搞明白网络引导到底怎么跑起来的爱好者。我会把 DHCP、TFTP、syslinux 三者的分工讲透把每一步配置背后的原因说清楚再把我自己在实操中遇到的坑和盘托出。你照着做大概率能一次跑通就算跑不通排查思路我也给你铺好了。需要提前说明的是本文所有操作都在一个隔离的内网实验环境中进行涉及的网段、主机名均为虚构示例你实际部署时替换成自己的规划即可。整个方案不依赖任何外部网络纯内网闭环这也是它适合企业环境的根本原因。2. 三件套的分工DHCP 给地址、TFTP 递文件、syslinux 管引导在动手敲命令之前必须先把这三个组件的职责边界搞清楚。很多人配了半天不成功根源就是没弄明白谁在什么时候干了什么。我用一个寄快递的类比来解释DHCP 是那个告诉你你家门牌号是多少的物业TFTP 是那个把包裹送到你家门口的快递员而 syslinux 则是包裹里那份怎么组装家具的说明书。三者缺一不可顺序也不能乱。2.1 DHCP 不只是发 IP它还负责指路大多数人印象里的 DHCP 就是自动分配 IP 地址但在 PXE 场景下它承担了一个更关键的职责告诉客户端去哪里找引导文件。这是通过 DHCP 报文里的next-server和filename两个选项实现的。next-server指向 TFTP 服务器的地址filename则指明要下载的引导文件名比如pxelinux.0。这里有个容易被忽略的点标准的 DHCP 服务比如dhcpd默认只处理普通地址分配要支持 PXE必须在配置里显式声明next-server和filename而且这两个选项通常要写在subnet或者host段里。如果你的网络里已经有了一台在跑的 DHCP 服务器那就得考虑是改造它还是新起一台——同一网段里跑两个 DHCP 会打架这个后面细说。2.2 TFTP 的简陋恰恰是它的优势TFTP 全称是简单文件传输协议基于 UDP 的 69 端口没有认证、没有目录列表、没有复杂的握手。听起来很原始但正因为足够简单它才能被固化在网卡的 PXE 固件里。你想想网卡 ROM 里那点存储空间根本塞不下一个完整的 FTP 或 HTTP 客户端而 TFTP 客户端实现起来可能就几百字节。TFTP 服务端我们一般用tftp-server这个包它的根目录默认在/var/lib/tftpboot。所有需要被客户端下载的文件——引导程序、内核、initrd——都得放在这个目录下而且权限要放开否则客户端读不到。这里有个经典坑SELinux 会拦截 TFTP 读取非标准目录的文件很多人文件明明放对了位置却下载失败就是被 SELinux 挡了。2.3 syslinux 是引导链的总调度syslinux 其实是一整个引导器家族针对不同介质有不同的变体syslinux用于 FAT 文件系统isolinux用于光盘pxelinux用于网络引导。我们在 PXE 场景下用的就是pxelinux.0这个文件。它的作用是被网卡下载并执行后去读取一个配置文件通常是pxelinux.cfg/default根据配置决定加载哪个内核、传什么参数、显示什么菜单。CentOS 8 里 syslinux 的版本和 7 有所不同配置文件语法基本兼容但一些路径和模块名有变化。比如ldlinux.c32这个模块在较新版本里是必须的缺了它pxelinux.0会报错找不到。这就是为什么很多人从 CentOS 7 迁移到 8 时明明照搬了旧配置却起不来——模块依赖变了。组件核心职责关键配置项常见坑点DHCP分配 IP 指明引导服务器和文件名next-server、filename与现有 DHCP 冲突、选项写错位置TFTP传输引导文件、内核、initrd根目录、文件权限SELinux 拦截、防火墙挡 UDP 69syslinux解析配置、加载内核、显示菜单pxelinux.0、pxelinux.cfg/default缺ldlinux.c32、配置路径错误把这三者的关系理顺了后面的配置就是按图索骥。我建议你在动手前先在纸上画出数据流向客户端广播 DHCP 请求 → DHCP 回应并告知 TFTP 地址和引导文件名 → 客户端向 TFTP 请求pxelinux.0→ 执行后请求配置文件 → 根据配置请求内核和 initrd → 启动安装程序。这条链路任何一环断了现象都不一样记住它排查时能省一半时间。3. 动手前的环境盘点与依赖安装配置这种事最怕的就是环境没摸清就上手。我见过太多人上来就yum install结果发现网卡没配好、防火墙没关、SELinux 在捣乱最后怀疑人生。所以这一章我们先做体检把地基打牢。3.1 网络规划把地址段和角色先定死在隔离实验环境里我习惯用192.168.100.0/24这个网段网关和 DHCP 服务器都放在192.168.100.1上TFTP 服务也跑在同一台机器。客户端则从192.168.100.100往后分配。为什么把服务端和网关放一起因为这样next-server直接写本机地址就行逻辑最简单也最不容易出错。你需要确认几件事服务端网卡的静态 IP 配好了没有、这个网段里有没有别的 DHCP 在跑、客户端和服务端是不是在同一个二层网络里。最后这点特别重要——DHCP 广播默认不跨网段如果你的客户端在另一个 VLAN就得配 DHCP 中继那是另一个话题了本文不展开。提示如果你的内网里已经有一台 DHCP 服务器在给其他机器发地址千万不要直接再起一台。正确做法是在原有 DHCP 配置里加上next-server和filename选项让它兼职做 PXE 引导。两台 DHCP 抢着回应会导致部分机器拿到错误配置现象非常诡异。3.2 安装三个核心软件包CentOS 8 的软件源里这三个包都是现成的一条命令搞定dnf install -y dhcp-server tftp-server syslinux注意包名是dhcp-server而不是dhcp这是 CentOS 8 和 7 的一个差异点7 里叫dhcp。tftp-server提供 TFTP 服务端syslinux则提供了pxelinux.0和一堆.c32模块文件。装完之后pxelinux.0通常在/usr/share/syslinux/目录下你可以先ls一下确认。装完别急着启动服务先把防火墙和 SELinux 这两个门神处理好。实验环境里我一般直接关掉它们省事但生产环境要按最小权限原则放行。TFTP 用的是 UDP 69DHCP 用的是 UDP 67 和 68这几个端口必须通。# 实验环境图省事直接停用 systemctl stop firewalld systemctl disable firewalld setenforce 0如果你坚持要开 SELinux那得给 TFTP 目录打上正确的上下文标签还要放行相关端口配置量不小。我个人的经验是内网隔离环境里先把功能跑通再逐步收紧安全策略比一上来就追求完美安全导致寸步难行要高效得多。3.3 准备安装源文件PXE 引导只是把机器叫醒真正装系统还得有安装源。最简单的方式是把 CentOS 8 的 ISO 镜像挂载到本地或者解压到某个目录然后通过 HTTP 或 NFS 共享出去。我这里用 HTTP 方式因为配置最简单客户端兼容性也最好。mkdir -p /var/www/html/centos8 mount -o loop /path/to/CentOS-8.iso /mnt cp -r /mnt/* /var/www/html/centos8/把 ISO 里的内容全部拷到 web 目录下这样客户端在安装阶段就能通过http://192.168.100.1/centos8访问到安装源。这一步很多人偷懒用mount --bind但重启后就失效了还是老老实实拷贝一份稳妥。拷贝完记得启动 HTTP 服务dnf install -y httpd systemctl enable --now httpd。4. 逐个击破DHCP、TFTP、syslinux 的配置实操环境备齐了现在进入正题。我会按数据流的顺序来配先 DHCP再 TFTP最后 syslinux。每配完一个我都会告诉你怎么单独验证它是否正常工作这样出问题时能快速定位是哪一环的锅。4.1 DHCP 配置把 next-server 和 filename 写对位置DHCP 的主配置文件在/etc/dhcp/dhcpd.conf默认是个空壳需要我们自己写。下面是我常用的一个最小可用配置# /etc/dhcp/dhcpd.conf option domain-name lab.local; option domain-name-servers 192.168.100.1; default-lease-time 600; max-lease-time 7200; authoritative; subnet 192.168.100.0 netmask 255.255.255.0 { range 192.168.100.100 192.168.100.200; option routers 192.168.100.1; next-server 192.168.100.1; filename pxelinux.0; }这里的关键就是next-server和filename这两行。next-server告诉客户端 TFTP 服务器在哪filename告诉它第一个要下载的文件叫啥。注意filename写的是相对路径相对于 TFTP 的根目录。有些人写成绝对路径/var/lib/tftpboot/pxelinux.0那是错的客户端会找不到。配完先别启动用dhcpd -t -cf /etc/dhcp/dhcpd.conf检查语法。这个命令能提前发现拼写错误和格式问题比启动失败后再翻日志高效得多。语法通过后systemctl enable --now dhcpd启动服务。验证 DHCP 是否正常最直接的办法是拿另一台机器或者虚拟机设成 DHCP 获取看能不能拿到192.168.100.x的地址。如果拿不到先看服务端日志journalctl -u dhcpd -f常见原因是网段写错、authoritative没加、或者防火墙挡了 UDP 67。4.2 TFTP 配置目录、权限、SELinux 三件事TFTP 的配置相对简单但坑一点不少。服务由tftp.socket这个 systemd 单元管理配置文件在/etc/systemd/system/tftp.service.d/或者直接改/usr/lib/systemd/system/tftp.service。不过大多数情况下默认配置就够用根目录就是/var/lib/tftpboot。systemctl enable --now tftp.socket启动后把 syslinux 的引导文件拷进去cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/ cp /usr/share/syslinux/ldlinux.c32 /var/lib/tftpboot/ cp /usr/share/syslinux/menu.c32 /var/lib/tftpboot/ cp /usr/share/syslinux/libutil.c32 /var/lib/tftpboot/ldlinux.c32是必须的前面提过缺了它pxelinux.0直接罢工。menu.c32和libutil.c32是为了做图形化启动菜单如果你不需要菜单可以不加但加上体验更好。验证 TFTP 是否工作可以在服务端本机装个客户端测试dnf install -y tftp tftp 192.168.100.1 tftp get pxelinux.0 tftp quit如果能下载成功说明 TFTP 服务本身没问题。如果报 Transfer timed out八成是防火墙或 SELinux。实验环境关了防火墙和 SELinux 的话基本不会遇到。生产环境记得放行 UDP 69 并给目录打标签。注意TFTP 根目录下的文件权限要保证tftp用户可读。默认pxelinux.0的权限是 644没问题。但如果你自己放内核文件进去别设成 600否则客户端下载会失败而且日志里不一定有明显报错很容易卡在这里。4.3 syslinux 引导菜单pxelinux.cfg 目录的命名玄机这是整个配置里最有意思的部分。pxelinux.0执行后会按一套特定的规则去寻找配置文件这个规则叫配置文件搜索顺序。它会依次尝试以下名字在pxelinux.cfg目录下用客户端 MAC 地址命名的文件格式是01-加上 MAC 地址横杠分隔比如01-52-54-00-12-34-56用客户端 IP 的十六进制表示命名的文件逐位缩短最后兜底的是default文件这套机制的设计意图是让你能给不同机器下发不同配置——比如给某台特定机器装特定版本。但绝大多数场景下我们只需要一个default文件就够了。mkdir -p /var/lib/tftpboot/pxelinux.cfg然后创建default文件# /var/lib/tftpboot/pxelinux.cfg/default default menu.c32 prompt 0 timeout 300 label centos8 menu label ^Install CentOS 8 kernel vmlinuz append initrdinitrd.img inst.repohttp://192.168.100.1/centos8 inst.kshttp://192.168.100.1/ks.cfg这里kernel和initrd指向的文件需要你从 ISO 的images/pxeboot/目录里拷到 TFTP 根目录cp /var/www/html/centos8/images/pxeboot/vmlinuz /var/lib/tftpboot/ cp /var/www/html/centos8/images/pxeboot/initrd.img /var/lib/tftpboot/append那行是精髓。inst.repo指定安装源地址inst.ks指定 Kickstart 自动应答文件。如果你只想手动安装把inst.ks去掉即可。Kickstart 文件放在 HTTP 目录下客户端安装时会自动拉取实现全自动无人值守。配置文件的语法有个细节label后面的名字是内部标识menu label才是显示给用户看的。^符号表示快捷键按I就能选中这一项。这些小细节能让你的启动菜单更专业。5. 联调验证从裸机到安装界面的完整链路配置都写完了现在是见证奇迹的时刻。但别急着开香槟联调阶段才是真正暴露问题的地方。我会带你走一遍完整的验证流程并告诉你每个环节该看什么现象。5.1 客户端侧的现象解读把一台裸机或虚拟机设成网络引导开机后你应该看到这样的过程网卡先是尝试 DHCP屏幕上出现类似DHCP...或者PXE-E51之类的提示。如果拿到地址会显示PXE-E53之后开始下载pxelinux.0。下载成功后syslinux 启动显示你配置的菜单。这里有几个典型现象对应不同问题卡在DHCP...不动DHCP 没响应检查服务端是否启动、网段是否匹配、防火墙是否放行报PXE-E32: TFTP open timeoutTFTP 连不上检查next-server地址、TFTP 服务状态、UDP 69 端口报PXE-E35: TFTP read timeout能连上但读不到文件检查文件名拼写、文件是否存在、权限是否正确下载完pxelinux.0后黑屏或报No configuration file foundpxelinux.cfg/default路径或名字不对菜单出来了但选完报错kernel或initrd文件缺失或者append参数里的安装源地址不通我建议你第一次联调时把虚拟机内存设大一点2G 以上因为 CentOS 8 的安装程序对内存有一定要求内存太小会在加载 initrd 阶段失败现象是卡在Loading initrd.img不动很容易误判成网络问题。5.2 用 tcpdump 抓包定位问题当现象不明确时抓包是最可靠的手段。在服务端跑tcpdump -i any -n port 67 or port 68 or port 69这条命令能同时看到 DHCP 和 TFTP 的交互。如果客户端发了 DHCP 请求但服务端没回说明请求没到或者服务端没处理如果服务端回了但客户端没继续请求 TFTP说明next-server或filename没被客户端接受。抓包看到的东西比日志直观得多尤其是排查到底哪一步断了的时候。5.3 Kickstart 自动安装的收尾如果你配了inst.ks客户端会自动完成分区、装包、设密码等操作全程无需干预。Kickstart 文件的内容这里不展开但有个经验值得分享ks.cfg里的url或repo地址必须和inst.repo一致否则会报找不到安装源。另外ks.cfg的权限要保证 HTTP 服务能读到放在/var/www/html/下一般没问题。自动安装完成后机器会自动重启。记得在 BIOS 里把启动顺序改回硬盘优先否则重启后又会进入 PXE 循环白白浪费时间。这个坑我踩过不止一次尤其是批量部署时几十台机器同时循环引导场面相当壮观。6. 那些让我熬夜的坑SELinux、防火墙与版本差异前面讲的都是顺利路径但真实世界里顺利是偶然踩坑是常态。这一章我把几个最折磨人的坑单独拎出来讲清楚它们的成因和排查方法。这些经验是文档里不会写的。6.1 SELinux 拦截 TFTP 的隐蔽性SELinux 最坑的地方在于它拦截时不一定给你明显的报错。客户端那边可能只是下载超时服务端日志里也可能只有一句含糊的拒绝。排查方法是看审计日志ausearch -m avc -ts recent如果看到和tftp相关的denied记录那就是 SELinux 在作祟。临时解决是setenforce 0永久解决是给 TFTP 目录打上tftpdir_rw_t标签或者用semanage放行。我个人的建议是内网实验环境直接关掉 SELinux把精力放在功能验证上生产环境再花时间做精细化的策略配置。6.2 防火墙的 UDP 陷阱防火墙对 TCP 的处理大家都很熟悉但 UDP 有个特点它是无连接的没有握手过程。这意味着如果 UDP 69 被挡客户端不会收到拒绝信号只会一直等直到超时。现象就是卡住而不是报错。这种沉默的失败最让人抓狂。排查时先用firewall-cmd --list-all看规则确认tftp服务有没有被放行。CentOS 8 的 firewalld 内置了tftp服务定义直接firewall-cmd --add-servicetftp --permanent就行。DHCP 同理--add-servicedhcp。加完记得--reload。6.3 CentOS 7 到 8 的引导文件差异如果你是从 CentOS 7 环境迁移过来的有几个差异必须注意。首先是包名dhcp变成了dhcp-server。其次是 syslinux 的模块文件CentOS 8 里ldlinux.c32是强依赖7 里某些版本可能不需要。再就是pxelinux.0的默认路径虽然都在/usr/share/syslinux/但个别小版本会有出入装完最好rpm -ql syslinux | grep pxelinux确认一下。还有一个隐蔽的差异CentOS 8 的安装程序对inst.repo的格式要求更严格必须写完整的 URL不能像 7 那样简写。这些差异单看都不大但叠加在一起就够你排查半天的。坑点现象根因解决SELinux 拦截TFTP 下载超时日志含糊目录上下文标签不对关 SELinux 或打标签防火墙挡 UDP客户端卡住无报错UDP 无连接静默丢弃放行 tftp/dhcp 服务缺 ldlinux.c32pxelinux.0 执行报错CentOS 8 强依赖该模块拷贝该文件到 TFTP 根目录双 DHCP 冲突部分机器拿到错误配置同网段两个 DHCP 抢答合并到一台或做中继7. 从能用到好用几个提升效率的实践心得功能跑通只是起点真正让这套环境好用还得靠一些细节打磨。这些是我在多次部署中攒下来的经验分享给你。7.1 用 MAC 绑定给特定机器定制配置前面提到pxelinux.cfg支持按 MAC 地址命名配置文件。这个特性在混合部署场景下特别有用。比如你有十台机器要装 CentOS 8两台要装别的系统就可以给那两台单独建一个以 MAC 命名的配置文件其余走default。MAC 地址的写法要注意全小写用横杠分隔前面加01-。比如 MAC 是52:54:00:12:34:56文件名就是01-52-54-00-12-34-56。写错了不会报错只会默默走default所以配完一定要核对。7.2 把常用内核参数固化进菜单append那行可以塞很多有用的参数。比如consolettyS0,115200可以把输出重定向到串口方便在没有显示器的机架上调试inst.text强制文本安装模式省资源ipdhcp显式指定网络配置方式。把这些参数按场景做成不同的菜单项用的时候直接选比每次手敲高效得多。7.3 日志是你的朋友但要会看DHCP 的日志在journalctl -u dhcpdTFTP 的日志相对少主要靠抓包。syslinux 阶段的报错则直接显示在客户端屏幕上。排查时养成先看现象、再抓包、最后翻日志的习惯比盲目重启服务有效得多。我见过太多人一遇到问题就systemctl restart结果把现场破坏了反而更难定位。7.4 备份你的配置这套环境一旦配好配置文件就那么几个dhcpd.conf、pxelinux.cfg/default、ks.cfg。把它们纳入版本管理或者定期备份下次迁移或重建时能省大量时间。尤其是ks.cfg里面往往包含分区方案和软件包列表是真正的知识沉淀。最后分享一个我自己的习惯每次部署完我都会在一台虚拟机上完整走一遍流程确认无误后再上物理机。虚拟机快照能让你大胆试错而物理机的一次失败可能意味着半小时的等待。这个习惯帮我避开了无数次配置看起来对但就是跑不通的尴尬。整套 DHCP、TFTP、syslinux 的组合说到底就是把引导这件事拆成三步走稳每一步都验证到位剩下的就是水到渠成。