1. 从一个尴尬的办公室断网事故说起很多人第一次接触 DHCP,都是被逼的。我印象特别深,早些年帮一个朋友的小工作室处理网络,二十来台机器,某天早上大家开机发现一半电脑上不了网,手动配的 IP 地址冲突了——有人图省事把两台机器的地址填成了一样的。那天上午的活儿基本全废在排查上。后来我给他们上了 DHCP 服务,这类破事就再没出现过。DHCP 的全称是 Dynamic Host Configuration Protocol,动态主机配置协议。说人话就是:局域网里有个“发号员”,谁连上网,它就自动发一个没被占用的 IP 地址、子网掩码、网关、DNS 这些参数,机器不用手动填,插上网线或者连上 WiFi 就能用。它解决的核心问题就两个:一是地址冲突,二是批量管理的效率。你想想,一个几百台设备的办公网,靠人工一台台配 IP、改网关,那简直是灾难。这篇内容我打算把 Linux 下搭 DHCP 服务这件事从头到尾讲透。适合谁看?刚入行的运维、自己折腾家庭实验室的爱好者、还有需要给小型办公网做网络规划的技术负责人。我会从原理讲到实操,从配置文件逐行拆解讲到排错链路,尽量把那些文档里不写、但实际会踩的坑都摆出来。你跟着走一遍,基本能独立搭起一套稳定可用的 DHCP 服务。2. DHCP 到底在背后干了什么2.1 四次握手:DISCOVER、OFFER、REQUEST、ACK要配好 DHCP,先得明白它怎么工作。客户端和服务器的交互,经典说法是“四步握手”,我习惯叫它“一问一答一确认一盖章”。第一步,客户端开机后发现自己没 IP,就往局域网广播一个DHCP DISCOVER包,意思是“谁是发号员?我要个地址”。这个包是广播的,因为客户端还不知道服务器在哪。第二步,服务器收到 DISCOVER,从地址池里挑一个空闲地址,回一个DHCP OFFER包,意思是“我这有个地址,你要不要”。如果局域网里有多个 DHCP 服务器,客户端可能收到多个 OFFER。第三步,客户端从收到的 OFFER 里选一个(通常是最先到的),再广播一个DHCP REQUEST,明确告诉所有服务器“我要这个地址了”。为什么还要广播?因为要让其他发过 OFFER 的服务器知道,它们的提议没被选中,可以把预留的地址收回去。第四步,被选中的服务器回一个DHCP ACK确认包,正式把地址“盖章”给客户端,同时附上租期、网关、DNS 等信息。到这一步,客户端才真正把地址配上,网络通了。提示:如果服务器觉得不能给这个地址(比如地址池空了,或者客户端请求的地址不合法),会回一个 DHCP NAK,客户端收到后就得重新从 DISCOVER 开始。理解这四步特别重要,因为后面排错时,你脑子里要能对应上“卡在哪一步”。比如客户端一直拿不到地址,可能是 DISCOVER 发出去了但没服务器应答;也可能是 OFFER 发了但 REQUEST 没到,等等。2.2 租期机制:为什么地址不是永久给你的DHCP 分配的地址是有“租期”的,不是永久归属。这个设计很聪明。租期到了,客户端要么续租,要么把地址还回去。为什么要这样?想象一个咖啡厅的 WiFi,每天来来往往几十上百台设备。如果每个连过的设备都永久占一个 IP,地址池很快就满了,新来的设备就没地址可用。租期机制让“离开的设备”自动把地址释放回池子,供后来者使用。租期一般分两个阶段续租。当租期过了一半(T1 时刻),客户端会主动向原服务器发单播 REQUEST 请求续租;如果服务器没响应,到了租期的 87.5%(T2 时刻),客户端会广播请求,看有没有其他服务器能接管。如果一直没人理,租期一到,客户端就得放弃这个地址,重新走 DISCOVER 流程。实际配置里,租期设多长有讲究。办公网这种设备相对固定的场景,可以设长一点,比如 8 小时到 1 天,减少续租带来的广播流量。而访客网络、会议室这种流动性大的,设短一点,比如 1 到 2 小时,加快地址回收。这个参数在配置文件里就是default-lease-time和max-lease-time。2.3 地址池、作用域与保留地址的关系几个概念容易混,我用自己的话捋一遍。地址池(pool / range)就是一段可以往外发的 IP 区间,比如 192.168.10.100 到 192.168.10.200。服务器只会从这个区间里挑地址发。作用域(subnet 声明)是一个更大的概念,它描述“这个网段是什么”,包括网络号、子网掩码、网关、DNS 这些。一个作用域里可以有一个或多个地址池。保留地址(host 声明)是针对特定设备的。比如打印机、服务器这类需要固定 IP 的设备,你可以根据它的 MAC 地址,每次都给它发同一个地址。这样既享受了 DHCP 自动管理的便利,又保证了地址固定。这三者的关系,我打个比方:作用域是“一个小区”,地址池是“小区里可分配的停车位”,保留地址是“某辆车的专属车位”。理解了这层,配置文件的结构就一目了然了。3. 动手之前:环境准备与软件选型3.1 选哪台机器当 DHCP 服务器DHCP 服务本身很轻量,对硬件要求极低,一台老旧的机器、一个树莓派都能胜任。但选机器时有几个点要注意。首先,这台机器最好有固定的 IP 地址。DHCP 服务器自己得有个稳定的地址,否则客户端续租时找不到它。所以服务器本身要么手动配静态 IP,要么在路由器上做 MAC 绑定。其次,考虑网络位置。DHCP 靠广播工作,默认只能服务同一个广播域(也就是同一个二层网络)内的客户端。如果你要跨网段分配地址,得靠 DHCP 中继(relay)功能,这个后面会讲。所以最简单的做法,是把 DHCP 服务器放在你要服务的那个网段里。第三,稳定性。DHCP 服务挂了,新设备就上不了网,虽然已连的设备短期内不受影响,但影响面还是不小。所以生产环境里,建议至少有两台 DHCP 服务器做冗余,或者用路由器自带的 DHCP 作为备份。3.2 主流实现:ISC DHCP 与 dnsmasq 怎么选Linux 下搭 DHCP,最常用的两个方案是ISC DHCP Server(软件包名通常是isc-dhcp-server或dhcp)和dnsmasq。ISC DHCP 是“正规军”,功能全、配置灵活,支持复杂的地址池、保留、中继、DDNS 联动等,适合中大型网络。缺点是配置文件语法相对繁琐,学习曲线陡一点。dnsmasq 是“轻骑兵”,一个进程同时提供 DHCP、DNS、TFTP 功能,配置极简,特别适合家庭网络、小型办公网、还有做 PXE 网络启动的场景。缺点是超大规模、超复杂策略下不如 ISC 灵活。我的建议是:如果你只是想给家里或小办公室发地址,dnsmasq 足够,配置几行就完事;如果你要管理多个网段、大量保留地址、还要和 DNS 动态更新联动,那就上 ISC DHCP。这篇我以 ISC DHCP 为主线讲,因为它的概念体系最完整,学会了再回头看 dnsmasq 会觉得非常简单。安装命令因发行版而异,Debian/Ubuntu 系:sudo apt update sudo apt install isc-dhcp-serverRHEL/CentOS 系:sudo yum install dhcp-server装完之后先别急着启动,因为默认配置是空的,直接启动会报错。我们先把配置文件写好。3.3 网络规划:先想清楚再动手动手写配置前,先在纸上(或者脑子里)把这几件事定下来:你要服务的网段是什么?比如 192.168.10.0/24。网关地址是多少?比如 192.168.10.1。地址池范围留哪一段?比如 192.168.10.100 到 192.168.10.200。哪些地址要留给静态设备?比如 192.168.10.2 到 192.168.10.99 留给服务器、打印机、网络设备。DNS 服务器用哪个?可以是运营商的,也可以是内网自建的。租期设多长?把这些定清楚,配置文件就是把这些信息翻译成语法而已。我见过太多人上来就抄配置,结果网段和自己的实际环境对不上,排查半天。规划这十分钟,能省你两小时。4. 逐行拆解 dhcpd.conf 配置文件4.1 全局参数段:那些影响所有客户端的设置ISC DHCP 的主配置文件通常在/etc/dhcp/dhcpd.conf(Debian 系)或/etc/dhcpd.conf(RHEL 系)。文件结构分两大块:全局参数和 subnet 声明。全局参数写在最前面,对所有作用域生效。一个典型的全局段长这样:option domain-name "example.lan"; option domain-name-servers 192.168.10.2, 8.8.8.8; default-lease-time 3600; max-lease-time 7200; authoritative;逐行说。option domain-name是给客户端设置的域名后缀,内网用的话随便起个本地域名就行。option domain-name-servers是 DNS 服务器地址,可以写多个,客户端会按顺序用。这里我写了内网 DNS 加一个公共 DNS 做兜底。default-lease-time是默认租期,单位秒,3600 就是一小时。max-lease-time是客户端能申请的最长租期,客户端可以主动请求更长的租期,但不会超过这个上限。authoritative这个参数很关键,意思是“我是这个网段的权威 DHCP 服务器”。加上它,当客户端请求一个不合法地址时,服务器会直接回 NAK 拒绝,而不是沉默。如果内网有多个 DHCP 服务器,这个参数要谨慎用,否则可能互相打架。单服务器环境建议加上。注意:option domain-name-servers后面如果写多个地址,用逗号分隔,不要用空格,否则语法报错。这个坑我踩过,配置文件检查时报错信息还不明显,找了好久。4.2 subnet 声明:一个网段的完整定义subnet 声明是配置的核心,它告诉服务器“这个网段长什么样,地址怎么发”。一个例子:subnet 192.168.10.0 netmask 255.255.255.0 { range 192.168.10.100 192.168.10.200; option routers 192.168.10.1; option subnet-mask 255.255.255.0; option broadcast-address 192.168.10.255; }subnet后面跟网络号和掩码,注意这里写的是网络号 192.168.10.0,不是网关地址。range定义地址池的起止。option routers就是网关,客户端拿到后会把默认路由指向它。option subnet-mask和option broadcast-address分别是子网掩码和广播地址。这里有个细节:subnet声明的网段必须和服务器自己某个网卡的网段匹配,否则 dhcpd 启动时会报“no subnet declaration for xxx”的错。因为服务器得知道从哪个网卡往外发这个网段的地址。如果你服务器有多张网卡,要确保配置的网段对应正确的网卡。4.3 固定地址绑定:给打印机和服务器留个座有些设备需要固定 IP,但又想走 DHCP 管理,这时候用 host 声明做 MAC 绑定:host printer { hardware ethernet 00:11:22:33:44:55; fixed-address 192.168.10.50; }host后面是自定义的名字,随便起。hardware ethernet是设备的 MAC 地址,fixed-address是要固定分配的地址。这样每次这台设备来请求,服务器都会给它 192.168.10.50。这里有个容易忽略的点:fixed-address的地址最好不要落在 range 地址池范围内。虽然 ISC DHCP 会优先保证固定地址不被动态分配出去,但把固定地址和动态池分开管理,逻辑更清晰,也避免以后排查时混淆。我一般把 2 到 99 留给固定设备,100 往后做动态池。MAC 地址怎么查?在客户端上ip link或ifconfig都能看到。注意 MAC 地址格式,冒号分隔,全小写或全大写都行,但别混用。4.4 多网段与 DHCP 中继的配置思路如果你的 DHCP 服务器要服务多个网段,而这些网段不在同一个二层网络里,就需要 DHCP 中继。中继的原理是:中继设备(通常是路由器或三层交换机)收到本网段的 DHCP 广播后,把它转成单播发给 DHCP 服务器,并在包里带上“我是从哪个网段来的”信息。服务器根据这个信息,从对应的 subnet 声明里挑地址。服务器端配置很简单,把多个 subnet 声明都写上就行:subnet 192.168.10.0 netmask 255.255.255.0 { range 192.168.10.100 192.168.10.200; option routers 192.168.10.1; } subnet 192.168.20.0 netmask 255.255.255.0 { range 192.168.20.100 192.168.20.200; option routers 192.168.20.1; }关键在于中继设备的配置,这个因设备而异,一般在路由器的“DHCP 中继”或“IP helper-address”里填上 DHCP 服务器的 IP。服务器这边只要保证每个网段都有对应的 subnet 声明即可。提示:跨网段中继时,服务器上不需要为每个网段都配网卡,它只要有一个网卡能和中继设备通信就行。地址是按 subnet 声明发的,不是按服务器网卡发的。5. 启动、验证与客户端实测5.1 指定监听网卡并启动服务Debian 系有个文件/etc/default/isc-dhcp-server,里面要指定服务器监听哪张网卡:INTERFACESv4="eth0"如果你不指定,服务可能起不来或者监听错网卡。RHEL 系则在/etc/sysconfig/dhcpd里配DHCPDARGS=eth0。配好后启动服务:sudo systemctl start isc-dhcp-server sudo systemctl enable isc-dhcp-server启动前强烈建议先做配置语法检查:sudo dhcpd -t -cf /etc/dhcp/dhcpd.conf-t是测试模式,只检查配置不真正启动。这个习惯能帮你提前发现语法错误,比服务启动失败后再翻日志高效得多。5.2 看日志确认握手过程服务起来后,最直接的验证方式是看日志。Debian 系日志在/var/log/syslog,RHEL 系在/var/log/messages,或者用journalctl -u isc-dhcp-server -f实时看。当有客户端来请求时,日志里会打印完整的四步握手过程,类似:DHCPDISCOVER from 00:11:22:33:44:55 via eth0 DHCPOFFER on 192.168.10.100 to 00:11:22:33:44:55 via eth0 DHCPREQUEST for 192.168.10.100 from 00:11:22:33:44:55 via eth0 DHCPACK on 192.168.10.100 to 00:11:22:33:44:55 via eth0看到这四行,说明一次分配成功了。如果只看到 DISCOVER 没有 OFFER,说明服务器没应答,可能是配置问题或网卡问题;如果 OFFER 发了但没 REQUEST,可能是客户端那边有问题,或者网络里有别的 DHCP 服务器抢答。5.3 租约文件:谁拿了什么地址一目了然服务器会把所有分配出去的租约记录在/var/lib/dhcp/dhcpd.leases(路径因发行版可能不同)。这个文件是排查问题的宝藏。里面每条记录长这样:lease 192.168.10.100 { starts 1 2024/01/01 08:00:00; ends 1 2024/01/01 09:00:00; binding state active; hardware ethernet 00:11:22:33:44:55; client-hostname "laptop-a"; }想知道某个地址被谁占了、租期什么时候到期,直接翻这个文件。我排查地址冲突时,第一步就是看这个文件,确认服务器到底把地址发给了哪些 MAC。5.4 客户端侧验证:从 ip 命令到抓包服务器端看着正常,还得在客户端确认。Linux 客户端上:sudo dhclient -v eth0-v是详细模式,会打印整个握手过程。或者直接看当前地址:ip addr show eth0Windows 客户端用ipconfig /release释放,再ipconfig /renew重新获取。macOS 用sudo ipconfig set en0 DHCP。如果客户端拿不到地址,最狠的排查手段是抓包:sudo tcpdump -i eth0 -n port 67 or port 6867 是服务器端口,68 是客户端端口。抓包能看到 DISCOVER 有没有发出去、OFFER 有没有回来,一眼定位问题在哪一环。这个技能在复杂网络里特别值钱。6. 那些文档不写但实际会踩的坑6.1 地址池和静态地址打架最常见的坑:地址池范围没规划好,把网关、服务器这些静态地址也圈进去了。结果某天 DHCP 把网关地址发给了一台普通电脑,全网瘫痪。避免方法很简单:地址池永远从静态地址段之后开始。比如网关是 .1,服务器用 .2 到 .99,那地址池就从 .100 开始。规划时画个表,把每个区间的用途标清楚,贴在配置文件注释里,以后自己或同事看都清楚。6.2 多 DHCP 服务器导致的“抢答”内网如果有两个 DHCP 服务器(比如路由器自带一个,你又搭了一个),客户端可能拿到错误的地址。表现是时好时坏,有的设备拿到对的,有的拿到错的。排查方法:抓包看 OFFER 是从哪个 IP 来的。如果发现两个服务器都在应答,要么关掉一个,要么用authoritative配合网段隔离。生产环境里,多服务器应该做冗余(主备或负载均衡),而不是各发各的。6.3 防火墙挡了 UDP 67/68DHCP 走 UDP 协议,服务器监听 67,客户端监听 68。如果服务器开了防火墙,很容易把这两个端口挡了,表现就是客户端一直拿不到地址,但服务器日志里连 DISCOVER 都看不到。放行规则(以 firewalld 为例):sudo firewall-cmd --add-service=dhcp --permanent sudo firewall-cmd --reloadiptables 的话:sudo iptables -A INPUT -p udp --dport 67 -j ACCEPT sudo iptables -A INPUT -p udp --dport 68 -j ACCEPT这个坑的迷惑性在于,服务器本地测试一切正常,就是客户端拿不到,很容易往配置上想,其实是防火墙。6.4 租约文件损坏或权限问题dhcpd.leases文件如果权限不对,或者内容损坏,服务可能起不来或者行为异常。正常权限应该是 dhcpd 用户可读写。如果服务启动报和 leases 文件相关的错,可以先备份后清空这个文件(服务停止状态下操作),让它重新生成。注意:清空租约文件意味着服务器“忘记”了所有已分配的地址,可能导致短暂的地址冲突。生产环境操作前要评估,最好在维护窗口做。6.5 虚拟机环境下的网卡和广播问题在虚拟机里搭 DHCP 服务,坑更多。比如虚拟机的网卡模式如果是 NAT,广播可能出不去;如果是桥接,要确保桥接到正确的物理网卡。还有虚拟交换机可能默认过滤某些广播包。我遇到过在虚拟机里搭好 DHCP,宿主机能拿到地址,但同网段其他物理机拿不到,最后发现是虚拟网络编辑器的广播设置问题。虚拟机环境排查时,先确认二层广播能不能通,这是 DHCP 的命脉。7. 让 DHCP 服务更稳的几个进阶思路7.1 主备冗余:一台挂了另一台顶上单台 DHCP 服务器是单点故障。要提升可用性,可以搭主备。ISC DHCP 支持 failover 模式,两台服务器通过 TCP 通信同步租约状态,一台主一台备,主的挂了备的自动接管。配置 failover 需要在两台服务器的配置文件里加failover peer声明,并互相指定对方地址。这个配置稍复杂,涉及primary和secondary角色、mclt(最大客户端延迟时间)等参数。搭好后,租约状态会实时同步,切换对客户端基本无感。如果觉得 failover 太重,简单点的做法是两台服务器配相同的地址池但错开范围,各自独立工作,也能在一定程度上避免单点。不过这种方式地址利用率低,且可能出现冲突,不如 failover 优雅。7.2 和 DNS 联动:地址变了域名也跟着变在动态环境里,客户端拿到的 IP 可能每次都不一样,但它的主机名是固定的。如果 DNS 记录不跟着更新,别人用主机名就找不到它。ISC DHCP 支持动态 DNS 更新(DDNS),可以在分配地址的同时,自动更新 DNS 服务器里的 A 记录和 PTR 记录。配置 DDNS 需要 DHCP 和 DNS 配合,通常用 TSIG 密钥做安全认证。DHCP 服务器在给客户端分配地址后,用密钥向 DNS 服务器发送更新请求。这样客户端的主机名始终解析到正确的地址,内网访问体验大大提升。7.3 监控与告警:别等用户报障才知道DHCP 服务平时很安静,出问题时往往是用不了网才被发现。主动监控能让你先于用户发现问题。可以监控几个指标:地址池使用率(快满了要提前扩容)、服务进程状态、租约文件增长情况、日志里的 NAK 和错误数量。简单做法是写个脚本定期检查,配合监控系统告警。比如统计租约文件里 active 状态的数量,超过池子 80% 就告警。7.4 日志分级与审计:出问题能追溯默认日志级别可能不够详细。可以在配置文件里调整日志级别,或者在启动参数里加-d开调试模式(仅排查时用,平时别开,日志量太大)。对于合规要求高的环境,DHCP 日志要保留足够长时间,记录谁在什么时候拿了什么地址。这个在追查安全事件时很有用——知道某个时间点某个 IP 对应哪台设备。8. 我个人的几条实操心得搭 DHCP 这件事,配置本身不难,难的是把网络规划清楚、把边界情况想到。我这些年下来,有几条体会特别深。第一,规划先行,配置在后。每次动手前,我一定先把网段、网关、地址池、静态段、租期这些列成表,确认无误再写配置。这个习惯帮我避免了很多返工。第二,日志和租约文件是最好的朋友。出问题时别瞎猜,先看日志确认握手到哪一步,再看租约文件确认地址分配情况,八成问题都能定位。第三,抓包技能值得花时间学。tcpdump看 DHCP 交互,比任何猜测都直接。尤其是多服务器、跨网段这种复杂场景,抓包能省你大量时间。第四,变更前备份配置和租约。改配置前把dhcpd.conf和dhcpd.leases都备份一份,出问题能快速回滚。这个习惯在关键时刻能救命。第五,别忽视文档。把网络规划、地址分配、保留地址清单写成文档,贴在配置文件注释里或者团队知识库里。半年后你自己回来看,会感谢当时的自己。DHCP 是个“配好就忘”的服务,但正因为平时不显眼,出问题时才更让人措手不及。把上面这些细节都照顾到,你的 DHCP 服务基本能做到长期稳定运行,让网络管理这件事真正省心。
1. 从一个尴尬的办公室断网事故说起很多人第一次接触 DHCP,都是被逼的。我印象特别深,早些年帮一个朋友的小工作室处理网络,二十来台机器,某天早上大家开机发现一半电脑上不了网,手动配的 IP 地址冲突了——有人图省事把两台机器的地址填成了一样的。那天上午的活儿基本全废在排查上。后来我给他们上了 DHCP 服务,这类破事就再没出现过。DHCP 的全称是 Dynamic Host Configuration Protocol,动态主机配置协议。说人话就是:局域网里有个“发号员”,谁连上网,它就自动发一个没被占用的 IP 地址、子网掩码、网关、DNS 这些参数,机器不用手动填,插上网线或者连上 WiFi 就能用。它解决的核心问题就两个:一是地址冲突,二是批量管理的效率。你想想,一个几百台设备的办公网,靠人工一台台配 IP、改网关,那简直是灾难。这篇内容我打算把 Linux 下搭 DHCP 服务这件事从头到尾讲透。适合谁看?刚入行的运维、自己折腾家庭实验室的爱好者、还有需要给小型办公网做网络规划的技术负责人。我会从原理讲到实操,从配置文件逐行拆解讲到排错链路,尽量把那些文档里不写、但实际会踩的坑都摆出来。你跟着走一遍,基本能独立搭起一套稳定可用的 DHCP 服务。2. DHCP 到底在背后干了什么2.1 四次握手:DISCOVER、OFFER、REQUEST、ACK要配好 DHCP,先得明白它怎么工作。客户端和服务器的交互,经典说法是“四步握手”,我习惯叫它“一问一答一确认一盖章”。第一步,客户端开机后发现自己没 IP,就往局域网广播一个DHCP DISCOVER包,意思是“谁是发号员?我要个地址”。这个包是广播的,因为客户端还不知道服务器在哪。第二步,服务器收到 DISCOVER,从地址池里挑一个空闲地址,回一个DHCP OFFER包,意思是“我这有个地址,你要不要”。如果局域网里有多个 DHCP 服务器,客户端可能收到多个 OFFER。第三步,客户端从收到的 OFFER 里选一个(通常是最先到的),再广播一个DHCP REQUEST,明确告诉所有服务器“我要这个地址了”。为什么还要广播?因为要让其他发过 OFFER 的服务器知道,它们的提议没被选中,可以把预留的地址收回去。第四步,被选中的服务器回一个DHCP ACK确认包,正式把地址“盖章”给客户端,同时附上租期、网关、DNS 等信息。到这一步,客户端才真正把地址配上,网络通了。提示:如果服务器觉得不能给这个地址(比如地址池空了,或者客户端请求的地址不合法),会回一个 DHCP NAK,客户端收到后就得重新从 DISCOVER 开始。理解这四步特别重要,因为后面排错时,你脑子里要能对应上“卡在哪一步”。比如客户端一直拿不到地址,可能是 DISCOVER 发出去了但没服务器应答;也可能是 OFFER 发了但 REQUEST 没到,等等。2.2 租期机制:为什么地址不是永久给你的DHCP 分配的地址是有“租期”的,不是永久归属。这个设计很聪明。租期到了,客户端要么续租,要么把地址还回去。为什么要这样?想象一个咖啡厅的 WiFi,每天来来往往几十上百台设备。如果每个连过的设备都永久占一个 IP,地址池很快就满了,新来的设备就没地址可用。租期机制让“离开的设备”自动把地址释放回池子,供后来者使用。租期一般分两个阶段续租。当租期过了一半(T1 时刻),客户端会主动向原服务器发单播 REQUEST 请求续租;如果服务器没响应,到了租期的 87.5%(T2 时刻),客户端会广播请求,看有没有其他服务器能接管。如果一直没人理,租期一到,客户端就得放弃这个地址,重新走 DISCOVER 流程。实际配置里,租期设多长有讲究。办公网这种设备相对固定的场景,可以设长一点,比如 8 小时到 1 天,减少续租带来的广播流量。而访客网络、会议室这种流动性大的,设短一点,比如 1 到 2 小时,加快地址回收。这个参数在配置文件里就是default-lease-time和max-lease-time。2.3 地址池、作用域与保留地址的关系几个概念容易混,我用自己的话捋一遍。地址池(pool / range)就是一段可以往外发的 IP 区间,比如 192.168.10.100 到 192.168.10.200。服务器只会从这个区间里挑地址发。作用域(subnet 声明)是一个更大的概念,它描述“这个网段是什么”,包括网络号、子网掩码、网关、DNS 这些。一个作用域里可以有一个或多个地址池。保留地址(host 声明)是针对特定设备的。比如打印机、服务器这类需要固定 IP 的设备,你可以根据它的 MAC 地址,每次都给它发同一个地址。这样既享受了 DHCP 自动管理的便利,又保证了地址固定。这三者的关系,我打个比方:作用域是“一个小区”,地址池是“小区里可分配的停车位”,保留地址是“某辆车的专属车位”。理解了这层,配置文件的结构就一目了然了。3. 动手之前:环境准备与软件选型3.1 选哪台机器当 DHCP 服务器DHCP 服务本身很轻量,对硬件要求极低,一台老旧的机器、一个树莓派都能胜任。但选机器时有几个点要注意。首先,这台机器最好有固定的 IP 地址。DHCP 服务器自己得有个稳定的地址,否则客户端续租时找不到它。所以服务器本身要么手动配静态 IP,要么在路由器上做 MAC 绑定。其次,考虑网络位置。DHCP 靠广播工作,默认只能服务同一个广播域(也就是同一个二层网络)内的客户端。如果你要跨网段分配地址,得靠 DHCP 中继(relay)功能,这个后面会讲。所以最简单的做法,是把 DHCP 服务器放在你要服务的那个网段里。第三,稳定性。DHCP 服务挂了,新设备就上不了网,虽然已连的设备短期内不受影响,但影响面还是不小。所以生产环境里,建议至少有两台 DHCP 服务器做冗余,或者用路由器自带的 DHCP 作为备份。3.2 主流实现:ISC DHCP 与 dnsmasq 怎么选Linux 下搭 DHCP,最常用的两个方案是ISC DHCP Server(软件包名通常是isc-dhcp-server或dhcp)和dnsmasq。ISC DHCP 是“正规军”,功能全、配置灵活,支持复杂的地址池、保留、中继、DDNS 联动等,适合中大型网络。缺点是配置文件语法相对繁琐,学习曲线陡一点。dnsmasq 是“轻骑兵”,一个进程同时提供 DHCP、DNS、TFTP 功能,配置极简,特别适合家庭网络、小型办公网、还有做 PXE 网络启动的场景。缺点是超大规模、超复杂策略下不如 ISC 灵活。我的建议是:如果你只是想给家里或小办公室发地址,dnsmasq 足够,配置几行就完事;如果你要管理多个网段、大量保留地址、还要和 DNS 动态更新联动,那就上 ISC DHCP。这篇我以 ISC DHCP 为主线讲,因为它的概念体系最完整,学会了再回头看 dnsmasq 会觉得非常简单。安装命令因发行版而异,Debian/Ubuntu 系:sudo apt update sudo apt install isc-dhcp-serverRHEL/CentOS 系:sudo yum install dhcp-server装完之后先别急着启动,因为默认配置是空的,直接启动会报错。我们先把配置文件写好。3.3 网络规划:先想清楚再动手动手写配置前,先在纸上(或者脑子里)把这几件事定下来:你要服务的网段是什么?比如 192.168.10.0/24。网关地址是多少?比如 192.168.10.1。地址池范围留哪一段?比如 192.168.10.100 到 192.168.10.200。哪些地址要留给静态设备?比如 192.168.10.2 到 192.168.10.99 留给服务器、打印机、网络设备。DNS 服务器用哪个?可以是运营商的,也可以是内网自建的。租期设多长?把这些定清楚,配置文件就是把这些信息翻译成语法而已。我见过太多人上来就抄配置,结果网段和自己的实际环境对不上,排查半天。规划这十分钟,能省你两小时。4. 逐行拆解 dhcpd.conf 配置文件4.1 全局参数段:那些影响所有客户端的设置ISC DHCP 的主配置文件通常在/etc/dhcp/dhcpd.conf(Debian 系)或/etc/dhcpd.conf(RHEL 系)。文件结构分两大块:全局参数和 subnet 声明。全局参数写在最前面,对所有作用域生效。一个典型的全局段长这样:option domain-name "example.lan"; option domain-name-servers 192.168.10.2, 8.8.8.8; default-lease-time 3600; max-lease-time 7200; authoritative;逐行说。option domain-name是给客户端设置的域名后缀,内网用的话随便起个本地域名就行。option domain-name-servers是 DNS 服务器地址,可以写多个,客户端会按顺序用。这里我写了内网 DNS 加一个公共 DNS 做兜底。default-lease-time是默认租期,单位秒,3600 就是一小时。max-lease-time是客户端能申请的最长租期,客户端可以主动请求更长的租期,但不会超过这个上限。authoritative这个参数很关键,意思是“我是这个网段的权威 DHCP 服务器”。加上它,当客户端请求一个不合法地址时,服务器会直接回 NAK 拒绝,而不是沉默。如果内网有多个 DHCP 服务器,这个参数要谨慎用,否则可能互相打架。单服务器环境建议加上。注意:option domain-name-servers后面如果写多个地址,用逗号分隔,不要用空格,否则语法报错。这个坑我踩过,配置文件检查时报错信息还不明显,找了好久。4.2 subnet 声明:一个网段的完整定义subnet 声明是配置的核心,它告诉服务器“这个网段长什么样,地址怎么发”。一个例子:subnet 192.168.10.0 netmask 255.255.255.0 { range 192.168.10.100 192.168.10.200; option routers 192.168.10.1; option subnet-mask 255.255.255.0; option broadcast-address 192.168.10.255; }subnet后面跟网络号和掩码,注意这里写的是网络号 192.168.10.0,不是网关地址。range定义地址池的起止。option routers就是网关,客户端拿到后会把默认路由指向它。option subnet-mask和option broadcast-address分别是子网掩码和广播地址。这里有个细节:subnet声明的网段必须和服务器自己某个网卡的网段匹配,否则 dhcpd 启动时会报“no subnet declaration for xxx”的错。因为服务器得知道从哪个网卡往外发这个网段的地址。如果你服务器有多张网卡,要确保配置的网段对应正确的网卡。4.3 固定地址绑定:给打印机和服务器留个座有些设备需要固定 IP,但又想走 DHCP 管理,这时候用 host 声明做 MAC 绑定:host printer { hardware ethernet 00:11:22:33:44:55; fixed-address 192.168.10.50; }host后面是自定义的名字,随便起。hardware ethernet是设备的 MAC 地址,fixed-address是要固定分配的地址。这样每次这台设备来请求,服务器都会给它 192.168.10.50。这里有个容易忽略的点:fixed-address的地址最好不要落在 range 地址池范围内。虽然 ISC DHCP 会优先保证固定地址不被动态分配出去,但把固定地址和动态池分开管理,逻辑更清晰,也避免以后排查时混淆。我一般把 2 到 99 留给固定设备,100 往后做动态池。MAC 地址怎么查?在客户端上ip link或ifconfig都能看到。注意 MAC 地址格式,冒号分隔,全小写或全大写都行,但别混用。4.4 多网段与 DHCP 中继的配置思路如果你的 DHCP 服务器要服务多个网段,而这些网段不在同一个二层网络里,就需要 DHCP 中继。中继的原理是:中继设备(通常是路由器或三层交换机)收到本网段的 DHCP 广播后,把它转成单播发给 DHCP 服务器,并在包里带上“我是从哪个网段来的”信息。服务器根据这个信息,从对应的 subnet 声明里挑地址。服务器端配置很简单,把多个 subnet 声明都写上就行:subnet 192.168.10.0 netmask 255.255.255.0 { range 192.168.10.100 192.168.10.200; option routers 192.168.10.1; } subnet 192.168.20.0 netmask 255.255.255.0 { range 192.168.20.100 192.168.20.200; option routers 192.168.20.1; }关键在于中继设备的配置,这个因设备而异,一般在路由器的“DHCP 中继”或“IP helper-address”里填上 DHCP 服务器的 IP。服务器这边只要保证每个网段都有对应的 subnet 声明即可。提示:跨网段中继时,服务器上不需要为每个网段都配网卡,它只要有一个网卡能和中继设备通信就行。地址是按 subnet 声明发的,不是按服务器网卡发的。5. 启动、验证与客户端实测5.1 指定监听网卡并启动服务Debian 系有个文件/etc/default/isc-dhcp-server,里面要指定服务器监听哪张网卡:INTERFACESv4="eth0"如果你不指定,服务可能起不来或者监听错网卡。RHEL 系则在/etc/sysconfig/dhcpd里配DHCPDARGS=eth0。配好后启动服务:sudo systemctl start isc-dhcp-server sudo systemctl enable isc-dhcp-server启动前强烈建议先做配置语法检查:sudo dhcpd -t -cf /etc/dhcp/dhcpd.conf-t是测试模式,只检查配置不真正启动。这个习惯能帮你提前发现语法错误,比服务启动失败后再翻日志高效得多。5.2 看日志确认握手过程服务起来后,最直接的验证方式是看日志。Debian 系日志在/var/log/syslog,RHEL 系在/var/log/messages,或者用journalctl -u isc-dhcp-server -f实时看。当有客户端来请求时,日志里会打印完整的四步握手过程,类似:DHCPDISCOVER from 00:11:22:33:44:55 via eth0 DHCPOFFER on 192.168.10.100 to 00:11:22:33:44:55 via eth0 DHCPREQUEST for 192.168.10.100 from 00:11:22:33:44:55 via eth0 DHCPACK on 192.168.10.100 to 00:11:22:33:44:55 via eth0看到这四行,说明一次分配成功了。如果只看到 DISCOVER 没有 OFFER,说明服务器没应答,可能是配置问题或网卡问题;如果 OFFER 发了但没 REQUEST,可能是客户端那边有问题,或者网络里有别的 DHCP 服务器抢答。5.3 租约文件:谁拿了什么地址一目了然服务器会把所有分配出去的租约记录在/var/lib/dhcp/dhcpd.leases(路径因发行版可能不同)。这个文件是排查问题的宝藏。里面每条记录长这样:lease 192.168.10.100 { starts 1 2024/01/01 08:00:00; ends 1 2024/01/01 09:00:00; binding state active; hardware ethernet 00:11:22:33:44:55; client-hostname "laptop-a"; }想知道某个地址被谁占了、租期什么时候到期,直接翻这个文件。我排查地址冲突时,第一步就是看这个文件,确认服务器到底把地址发给了哪些 MAC。5.4 客户端侧验证:从 ip 命令到抓包服务器端看着正常,还得在客户端确认。Linux 客户端上:sudo dhclient -v eth0-v是详细模式,会打印整个握手过程。或者直接看当前地址:ip addr show eth0Windows 客户端用ipconfig /release释放,再ipconfig /renew重新获取。macOS 用sudo ipconfig set en0 DHCP。如果客户端拿不到地址,最狠的排查手段是抓包:sudo tcpdump -i eth0 -n port 67 or port 6867 是服务器端口,68 是客户端端口。抓包能看到 DISCOVER 有没有发出去、OFFER 有没有回来,一眼定位问题在哪一环。这个技能在复杂网络里特别值钱。6. 那些文档不写但实际会踩的坑6.1 地址池和静态地址打架最常见的坑:地址池范围没规划好,把网关、服务器这些静态地址也圈进去了。结果某天 DHCP 把网关地址发给了一台普通电脑,全网瘫痪。避免方法很简单:地址池永远从静态地址段之后开始。比如网关是 .1,服务器用 .2 到 .99,那地址池就从 .100 开始。规划时画个表,把每个区间的用途标清楚,贴在配置文件注释里,以后自己或同事看都清楚。6.2 多 DHCP 服务器导致的“抢答”内网如果有两个 DHCP 服务器(比如路由器自带一个,你又搭了一个),客户端可能拿到错误的地址。表现是时好时坏,有的设备拿到对的,有的拿到错的。排查方法:抓包看 OFFER 是从哪个 IP 来的。如果发现两个服务器都在应答,要么关掉一个,要么用authoritative配合网段隔离。生产环境里,多服务器应该做冗余(主备或负载均衡),而不是各发各的。6.3 防火墙挡了 UDP 67/68DHCP 走 UDP 协议,服务器监听 67,客户端监听 68。如果服务器开了防火墙,很容易把这两个端口挡了,表现就是客户端一直拿不到地址,但服务器日志里连 DISCOVER 都看不到。放行规则(以 firewalld 为例):sudo firewall-cmd --add-service=dhcp --permanent sudo firewall-cmd --reloadiptables 的话:sudo iptables -A INPUT -p udp --dport 67 -j ACCEPT sudo iptables -A INPUT -p udp --dport 68 -j ACCEPT这个坑的迷惑性在于,服务器本地测试一切正常,就是客户端拿不到,很容易往配置上想,其实是防火墙。6.4 租约文件损坏或权限问题dhcpd.leases文件如果权限不对,或者内容损坏,服务可能起不来或者行为异常。正常权限应该是 dhcpd 用户可读写。如果服务启动报和 leases 文件相关的错,可以先备份后清空这个文件(服务停止状态下操作),让它重新生成。注意:清空租约文件意味着服务器“忘记”了所有已分配的地址,可能导致短暂的地址冲突。生产环境操作前要评估,最好在维护窗口做。6.5 虚拟机环境下的网卡和广播问题在虚拟机里搭 DHCP 服务,坑更多。比如虚拟机的网卡模式如果是 NAT,广播可能出不去;如果是桥接,要确保桥接到正确的物理网卡。还有虚拟交换机可能默认过滤某些广播包。我遇到过在虚拟机里搭好 DHCP,宿主机能拿到地址,但同网段其他物理机拿不到,最后发现是虚拟网络编辑器的广播设置问题。虚拟机环境排查时,先确认二层广播能不能通,这是 DHCP 的命脉。7. 让 DHCP 服务更稳的几个进阶思路7.1 主备冗余:一台挂了另一台顶上单台 DHCP 服务器是单点故障。要提升可用性,可以搭主备。ISC DHCP 支持 failover 模式,两台服务器通过 TCP 通信同步租约状态,一台主一台备,主的挂了备的自动接管。配置 failover 需要在两台服务器的配置文件里加failover peer声明,并互相指定对方地址。这个配置稍复杂,涉及primary和secondary角色、mclt(最大客户端延迟时间)等参数。搭好后,租约状态会实时同步,切换对客户端基本无感。如果觉得 failover 太重,简单点的做法是两台服务器配相同的地址池但错开范围,各自独立工作,也能在一定程度上避免单点。不过这种方式地址利用率低,且可能出现冲突,不如 failover 优雅。7.2 和 DNS 联动:地址变了域名也跟着变在动态环境里,客户端拿到的 IP 可能每次都不一样,但它的主机名是固定的。如果 DNS 记录不跟着更新,别人用主机名就找不到它。ISC DHCP 支持动态 DNS 更新(DDNS),可以在分配地址的同时,自动更新 DNS 服务器里的 A 记录和 PTR 记录。配置 DDNS 需要 DHCP 和 DNS 配合,通常用 TSIG 密钥做安全认证。DHCP 服务器在给客户端分配地址后,用密钥向 DNS 服务器发送更新请求。这样客户端的主机名始终解析到正确的地址,内网访问体验大大提升。7.3 监控与告警:别等用户报障才知道DHCP 服务平时很安静,出问题时往往是用不了网才被发现。主动监控能让你先于用户发现问题。可以监控几个指标:地址池使用率(快满了要提前扩容)、服务进程状态、租约文件增长情况、日志里的 NAK 和错误数量。简单做法是写个脚本定期检查,配合监控系统告警。比如统计租约文件里 active 状态的数量,超过池子 80% 就告警。7.4 日志分级与审计:出问题能追溯默认日志级别可能不够详细。可以在配置文件里调整日志级别,或者在启动参数里加-d开调试模式(仅排查时用,平时别开,日志量太大)。对于合规要求高的环境,DHCP 日志要保留足够长时间,记录谁在什么时候拿了什么地址。这个在追查安全事件时很有用——知道某个时间点某个 IP 对应哪台设备。8. 我个人的几条实操心得搭 DHCP 这件事,配置本身不难,难的是把网络规划清楚、把边界情况想到。我这些年下来,有几条体会特别深。第一,规划先行,配置在后。每次动手前,我一定先把网段、网关、地址池、静态段、租期这些列成表,确认无误再写配置。这个习惯帮我避免了很多返工。第二,日志和租约文件是最好的朋友。出问题时别瞎猜,先看日志确认握手到哪一步,再看租约文件确认地址分配情况,八成问题都能定位。第三,抓包技能值得花时间学。tcpdump看 DHCP 交互,比任何猜测都直接。尤其是多服务器、跨网段这种复杂场景,抓包能省你大量时间。第四,变更前备份配置和租约。改配置前把dhcpd.conf和dhcpd.leases都备份一份,出问题能快速回滚。这个习惯在关键时刻能救命。第五,别忽视文档。把网络规划、地址分配、保留地址清单写成文档,贴在配置文件注释里或者团队知识库里。半年后你自己回来看,会感谢当时的自己。DHCP 是个“配好就忘”的服务,但正因为平时不显眼,出问题时才更让人措手不及。把上面这些细节都照顾到,你的 DHCP 服务基本能做到长期稳定运行,让网络管理这件事真正省心。