1. 为什么还要自己搭 DHCP 服务
很多人第一次接触 DHCP 是在家里路由器上,插上网线自动拿到 IP,觉得这东西“天生就有”。直到某天你手里有三十台测试机、几台虚拟机、一堆开发板,才发现手动配 IP 是场灾难:改一个网段要挨个登机器,IP 冲突排查半天,换台设备忘了回收旧地址,第二天同事说“我连不上了”。
DHCP 服务就是来解决这个问题的。它负责在局域网里自动分配 IP 地址、子网掩码、网关、DNS 等参数,让设备接入网络时“开箱即用”。在 Linux 上搭 DHCP,核心是用isc-dhcp-server这个老牌实现(也有 dnsmasq、Kea 等替代品,后面会对比)。它适合谁?适合手里有小型机房、实验室网络、虚拟化集群、嵌入式开发环境的运维或开发者,也适合想搞懂“自动获取 IP”背后到底发生了什么的同学。
我自己第一次配 DHCP 是在一个二十来台机器的测试环境里,当时用静态 IP 表格管理,结果一台机器重装系统后 IP 忘了改,和另一台撞了,整个下午都在查为什么服务时通时断。从那以后我就把 DHCP 当成了内网基础设施的标配。这篇文章就把我踩过的坑、调过的参数、排查问题的思路完整梳理一遍,你照着做基本能一次跑通。
2. 先搞懂 DHCP 的工作流程与核心概念
2.1 四次握手到底在干什么
DHCP 分配地址的过程常被概括为 DORA 四步:Discover、Offer、Request、Ack。用生活化的类比,这就像你去一家餐厅吃饭:
- Discover:你进门喊一声“还有位子吗?”——客户端广播寻找 DHCP 服务器。
- Offer:服务员回应“有,靠窗那桌可以”——服务器从地址池挑一个可用 IP 回应。
- Request:你说“好,我就要那桌”——客户端正式请求使用该 IP。
- Ack:服务员确认“那桌归你了”——服务器确认租约,客户端配置生效。
这里有个容易被忽略的点:Discover 是广播,所以 DHCP 服务器必须和客户端在同一广播域,或者通过中继代理转发。跨网段部署时,路由器上要配ip helper-address指向 DHCP 服务器,否则客户端喊破喉咙也没人应。
2.2 租约、地址池与保留地址
DHCP 分配的 IP 不是永久给你的,而是“租”给你一段时间,这就是租约(lease)。租约到期前客户端会尝试续租,续租失败就重新走 DORA。租约时间设多长有讲究:办公网设备相对固定,可以设 8 小时到 1 天;测试环境设备频繁上下线,设 1 到 2 小时更合适,能让地址快速回收。
地址池(range)是服务器可分配的 IP 范围。保留地址(host 声明)则是给特定 MAC 绑定固定 IP,比如打印机、服务器、网络设备。保留地址不参与动态分配,避免被别的机器抢走。
2.3 为什么选 isc-dhcp-server
Linux 上能提供 DHCP 的软件不少,常见的有三个:
| 软件 | 特点 | 适用场景 |
|---|---|---|
| isc-dhcp-server | 功能全、配置直观、资料多 | 中小型网络、学习实验 |
| dnsmasq | 轻量,DHCP+DNS 一体 | 家庭、小型办公、嵌入式 |
| Kea | ISC 新一代,支持数据库后端 | 大型网络、需要 API 管理 |
我选 isc-dhcp-server 的理由很直接:配置文件结构清晰,subnet、range、host这些声明一看就懂,出问题日志也够详细。dnsmasq 虽然轻,但配置项偏少,做复杂保留和分组时不够灵活。Kea 功能强但上手成本高,小环境没必要。所以下面全部以 isc-dhcp-server 为主线。
3. 安装与基础配置实操
3.1 安装前的网络规划
动手之前先把这几件事定下来,不然后面改配置会反复重启服务:
- 服务器自己的 IP 必须是静态的。DHCP 服务器如果自己都靠 DHCP 拿地址,那就是鸡生蛋问题。用
nmcli或直接改/etc/netplan/把服务器网卡设成静态。 - 确定要服务的网段,比如
192.168.10.0/24。 - 划出地址池,比如
192.168.10.100到192.168.10.200,前 100 个留给静态设备和保留地址。 - 确认网关和 DNS,比如网关
192.168.10.1,DNS 可以用内网 DNS 或公共 DNS。
提示:地址池不要和静态设备所在区间重叠,否则会出现“明明配了静态 IP,却被 DHCP 分给别人”的冲突。
3.2 安装软件包
不同发行版命令不同,主流两种:
# Debian / Ubuntu 系 sudo apt update sudo apt install isc-dhcp-server # RHEL / CentOS / Rocky 系 sudo dnf install dhcp-server装完后 Debian 系可能会因为没配网卡而启动失败,这是正常的,先别急,配好再启动。
3.3 指定监听网卡
Debian/Ubuntu 上编辑/etc/default/isc-dhcp-server:
INTERFACESv4="eth0"把eth0换成你实际对外提供 DHCP 的网卡名,用ip a查看。如果服务器有多张网卡,只写内网那张,别把外网口也写进去,否则可能给不该服务的网段发地址。
RHEL 系则在/etc/dhcp/dhcpd.conf里通过subnet声明隐式确定,或者用DHCPDARGS在/etc/sysconfig/dhcpd里指定。
3.4 主配置文件结构
/etc/dhcp/dhcpd.conf是核心。一个最小可用配置长这样:
# 全局参数 default-lease-time 3600; max-lease-time 7200; option subnet-mask 255.255.255.0; option routers 192.168.10.1; option domain-name-servers 192.168.10.1, 8.8.8.8; option domain-name "lab.local"; # 声明网段 subnet 192.168.10.0 netmask 255.255.255.0 { range 192.168.10.100 192.168.10.200; } # 保留地址示例 host printer { hardware ethernet 00:11:22:33:44:55; fixed-address 192.168.10.50; }逐行解释一下:default-lease-time是默认租约秒数,max-lease-time是客户端能申请的最长租约。option routers就是网关,option domain-name-servers是 DNS。subnet块里必须写range,否则这个网段不会分配地址。host块用 MAC 绑定固定 IP,MAC 要写对,大小写无所谓但冒号不能少。
注意:每个
subnet声明必须和服务器某张网卡的网段匹配,否则 dhcpd 启动时会报 “no subnet declaration for xxx”,直接拒绝启动。
4. 进阶配置与参数调优
4.1 多网段与中继场景
如果内网分了 VLAN,比如192.168.10.0/24和192.168.20.0/24,服务器在一张网卡上,就需要在配置文件里写两个subnet块,并确保路由器上配了 DHCP 中继指向服务器。中继会把客户端的 Discover 单播转发给服务器,服务器根据请求来源的网关地址判断该用哪个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; }这里的关键是:服务器要能区分请求来自哪个网段。中继代理会在转发时带上giaddr字段,dhcpd 靠它选subnet。如果没配中继,跨网段是拿不到地址的。
4.2 租约时间怎么算
租约时间不是拍脑袋定的。一个简单的估算方法:假设地址池有 100 个地址,你预计同时在线设备最多 80 台,设备平均在线时长 4 小时,那租约设 4 到 8 小时比较合理。设太短,续租流量大;设太长,设备走了地址不释放,新设备可能拿不到。
我一般这么配:
- 办公/固定设备:
default-lease-time 28800;(8 小时) - 测试/临时设备:
default-lease-time 3600;(1 小时) - 访客网络:
default-lease-time 1800;(30 分钟)
4.3 保留地址与分组管理
保留地址除了绑 MAC,还可以用group把一组设备放一起,统一给参数。比如给所有打印机单独一个组:
group { option domain-name-servers 192.168.10.1; host printer-a { hardware ethernet 00:11:22:33:44:55; fixed-address 192.168.10.51; } host printer-b { hardware ethernet 00:11:22:33:44:66; fixed-address 192.168.10.52; } }这样管理起来清晰,改 DNS 只改一处。保留地址的 IP 一定要在range之外,否则可能和动态分配冲突。
4.4 配置文件语法检查
改完配置别急着重启,先跑一遍语法检查:
sudo dhcpd -t -cf /etc/dhcp/dhcpd.conf没有输出通常就是没问题,有错误会直接告诉你哪一行。这个习惯能省掉很多“服务起不来但不知道哪错”的时间。
5. 启动服务与客户端验证
5.1 启动并设置开机自启
# Debian / Ubuntu sudo systemctl restart isc-dhcp-server sudo systemctl enable isc-dhcp-server # RHEL 系 sudo systemctl restart dhcpd sudo systemctl enable dhcpd启动后立刻看状态:
sudo systemctl status isc-dhcp-server如果失败,八成是网卡名写错、subnet和网卡不匹配、或者配置文件语法错误。日志用journalctl -u isc-dhcp-server -n 50看最近 50 行。
5.2 服务端日志观察
dhcpd 的日志会记录每次分配。Debian 系默认可能写到 syslog,用:
sudo journalctl -u isc-dhcp-server -f能看到类似DHCPDISCOVER from 00:11:22:33:44:77 via eth0、DHCPOFFER on 192.168.10.100 to ...、DHCPACK on 192.168.10.100 to ...的记录。看到 DHCPACK 就说明分配成功了。
5.3 客户端验证
在另一台机器上把网卡设成 DHCP,然后:
# 释放旧地址 sudo dhclient -r eth0 # 重新获取 sudo dhclient -v eth0-v会打印详细过程,能看到 DORA 四步。拿到地址后用ip a确认 IP,ip route确认网关,cat /etc/resolv.conf确认 DNS。三样都对,才算真正配好。
5.4 租约文件在哪
服务器分配的租约记录在/var/lib/dhcp/dhcpd.leases。这个文件能看到当前所有已分配地址、对应 MAC、租约起止时间。排查“谁占了这个 IP”时直接翻它:
grep "192.168.10.100" /var/lib/dhcp/dhcpd.leases注意:这个文件不要手动编辑,dhcpd 自己维护。要看历史分配,可以定期备份它。
6. 常见问题与排查速查
6.1 服务起不来
最常见的三个原因:网卡名写错、subnet声明和实际网段不匹配、配置文件缺分号。用dhcpd -t先查语法,再用ip a核对网段。如果报 “no subnet declaration”,就是某个网卡没有对应的subnet块,要么补上,要么在/etc/default/isc-dhcp-server里只保留需要服务的网卡。
6.2 客户端拿不到地址
按这个顺序查:
- 客户端和服务器是否在同一广播域?跨网段有没有配中继?
- 服务器防火墙有没有放行 UDP 67/68?
sudo ufw allow 67/udp和68/udp。 - 地址池是不是满了?看租约文件里已分配数量。
- 服务器日志有没有收到 Discover?没收到就是网络层问题,收到了没 Offer 就是配置问题。
6.3 IP 冲突
冲突通常来自静态设备配了地址池内的 IP。解决办法是把静态设备移出range,或者给它们做保留。已经冲突的,用arping查哪个 MAC 在响应:
sudo arping -I eth0 192.168.10.1006.4 排查速查表
| 现象 | 可能原因 | 处理 |
|---|---|---|
| 服务启动失败 | 网卡名错/语法错 | dhcpd -t+ 核对网卡 |
| 客户端无响应 | 防火墙/跨网段 | 放行 67/68,配中继 |
| 地址池耗尽 | 租约太长/设备多 | 缩短租约,扩大 range |
| IP 冲突 | 静态占用池内地址 | 移出 range 或做保留 |
| 续租失败 | 服务器重启/网络断 | 查日志,确认服务在线 |
6.5 几个我踩过的坑
第一个坑:在虚拟化环境里,宿主机和虚拟机共用一张网卡做桥接,结果 DHCP 把地址分给了宿主机自己,导致虚拟机拿不到。后来把监听网卡限定为桥接接口才解决。
第二个坑:租约文件权限不对,dhcpd 启动时报无法写入。检查/var/lib/dhcp/属主是不是dhcpd。
第三个坑:改完配置只 reload 没 restart,某些参数不生效。涉及subnet结构变更时,老老实实 restart。
7. 安全加固与日常维护
7.1 限制服务范围
DHCP 最大的风险是“谁都能拿地址”。在交换机上配 DHCP Snooping,只信任连向 DHCP 服务器的端口,能挡住私接的假 DHCP。服务器侧则确保只监听内网网卡,别把服务暴露到不该去的网段。
7.2 定期检查租约
写个简单脚本定期统计租约使用率:
total=$(grep -c "^lease" /var/lib/dhcp/dhcpd.leases) echo "当前租约数: $total"使用率超过 80% 就该考虑扩池或缩短租约了。
7.3 备份配置
/etc/dhcp/dhcpd.conf和/var/lib/dhcp/dhcpd.leases定期备份。配置丢了重建很痛苦,租约丢了只是重新分配,但保留地址的绑定关系在配置里,所以配置最重要。
7.4 日志轮转
dhcpd 日志量大时,配好 logrotate,避免把磁盘写满。Debian 系一般自带/etc/logrotate.d/isc-dhcp-server,确认一下就行。
8. 替代方案与选型建议
如果你的场景更简单,比如就十几台设备,dnsmasq 一个配置文件搞定 DHCP+DNS,资源占用小,适合跑在树莓派或软路由上。如果网络规模上百台、需要 API 动态管理租约、要接数据库,那 Kea 更合适,它支持 MySQL/PostgreSQL 后端,还能通过 REST API 查询和修改租约。
我自己的选择逻辑是:学习和小型实验用 isc-dhcp-server,家庭网络用 dnsmasq,公司级大规模用 Kea。三者不冲突,按需选就行。
最后分享一个实用小技巧:调试阶段把default-lease-time设成 60 秒,这样客户端频繁续租,你能在日志里快速看到完整交互过程,确认没问题后再改回正常值。这个办法帮我省了很多“等半天才看到一次分配”的时间。