DHCP mini-HOWTO: Linux DHCP clients and Kea or dnsmasq servers

Updated November 2026

DHCP hands out IP addresses, the default gateway and DNS servers automatically. On a Linux client you rarely touch it: NetworkManager or systemd-networkd does the work. For a server, the old ISC dhcpd has been end of life since the end of 2022; use Kea for real networks or dnsmasq for a small LAN.

The classic DHCP mini-HOWTO from 2000 is kept by the Linux Documentation Project at tldp.org. This page covers current releases as of November 2026.

How a lease works

A new client broadcasts DHCPDISCOVER on UDP port 67. Servers reply with an offer, the client requests one offer, and the chosen server acknowledges it. The client may then use the address for the lease time. Halfway through, it tries to renew with the same server; if that fails, it asks any server later on. Every lease carries options: the subnet mask, router (option 3), DNS servers (option 6), domain name, and more. Because DHCP starts with broadcasts, a server only sees clients on its own network segment unless a router relays the requests.

Client side

NetworkManager

Fedora, RHEL and its clones, and desktop installs of Debian and Ubuntu use NetworkManager. Its built-in (“internal”) DHCP client is the default; the other choices for the dhcp= setting in NetworkManager.conf depend on how your distribution built NetworkManager (the upstream manual lists internal and dhcpcd). A wired profile uses DHCP unless you set a static address:

nmcli device status
nmcli connection show
sudo nmcli connection modify "Wired connection 1" ipv4.method auto ipv6.method auto
sudo nmcli connection up "Wired connection 1"   # re-runs DHCP
nmcli -f DHCP4 device show enp1s0               # the lease and its options

systemd-networkd

Servers and minimal installs often use systemd-networkd (Ubuntu Server writes its files through netplan). A DHCP interface needs only a .network file, for example /etc/systemd/network/20-wired.network:

[Match]
Name=enp1s0

[Network]
DHCP=yes

DHCP= accepts yes, no, ipv4 or ipv6. Apply and check:

sudo networkctl reload
networkctl status enp1s0
sudo networkctl renew enp1s0

dhclient and dhcpcd

dhclient is part of the ISC DHCP suite and is no longer maintained upstream. Debian 13 still packages it (isc-dhcp-client), and classic ifupdown (/etc/network/interfaces with iface eth0 inet dhcp) tries dhclient, then udhcpc, then dhcpcd, whichever is installed. Installing dhcpcd-base gives ifupdown a maintained client. On new systems, prefer NetworkManager or networkd.

Which server to run

DHCP servers on Linux as of November 2026
ServerStatusGood for
ISC dhcpdEnd of maintenance since end of 2022; last releases 4.4.3-P1 and 4.1-ESV-R16-P2 (October 2022)Nothing new; migrate away
ISC KeaMaintained. Upstream branches: 3.0 (long-term support), 3.2 (stable), 3.3 (development). Debian 13 ships 2.6; Fedora 43 and 44 ship 3.0, Fedora 45 ships 3.2; RHEL 10 documents Kea as its DHCP serverOffices, campuses, ISPs; JSON config, REST API, database back ends, high availability
dnsmasqMaintainedHome and small office routers; DHCP and DNS caching in one small daemon
systemd-networkdMaintainedA simple server on one interface, such as a lab or VM network

Run only one DHCP server per network segment, and switch off the DHCP server in your Internet router if Linux takes over.

Kea DHCPv4 server

# Debian / Ubuntu
sudo apt install kea-dhcp4-server
# Fedora / RHEL 10 / Alma / Rocky — the package is "kea"
sudo dnf install kea

Both put the config in /etc/kea/kea-dhcp4.conf. The service is kea-dhcp4-server on Debian and Ubuntu and kea-dhcp4 on Fedora. ISC also publishes its own packages for current branches. This complete file serves 192.168.1.0/24 on interface enp2s0, with the router and DNS server at 192.168.1.1 and one fixed address:

{
  "Dhcp4": {
    "interfaces-config": {
      "interfaces": [ "enp2s0" ]
    },
    "lease-database": {
      "type": "memfile",
      "persist": true,
      "lfc-interval": 3600
    },
    "valid-lifetime": 43200,
    "renew-timer": 21600,
    "rebind-timer": 37800,
    "option-data": [
      { "name": "domain-name-servers", "data": "192.168.1.1" },
      { "name": "domain-name", "data": "lan" }
    ],
    "subnet4": [
      {
        "id": 1,
        "subnet": "192.168.1.0/24",
        "pools": [
          { "pool": "192.168.1.100 - 192.168.1.199" }
        ],
        "option-data": [
          { "name": "routers", "data": "192.168.1.1" }
        ],
        "reservations": [
          {
            "hw-address": "52:54:00:12:34:56",
            "ip-address": "192.168.1.20",
            "hostname": "nas"
          }
        ]
      }
    ]
  }
}

Times are in seconds: a 43,200-second lease is 12 hours, renewal starts at 6 hours (21,600) and rebinding at 10.5 hours (37,800). The file is JSON: no trailing commas, every string in double quotes. Give every subnet a unique, stable id. Keep reserved addresses outside the pool (here .20 is below .100) so Kea never hands them to another machine.

Test the file, then start the server:

sudo kea-dhcp4 -t /etc/kea/kea-dhcp4.conf && echo OK
sudo systemctl enable --now kea-dhcp4-server     # Fedora: kea-dhcp4
journalctl -u kea-dhcp4-server -f

-t parses and checks the file and exits with 0 when it is valid; it also fails if the named interface does not exist on the machine. Leases are written to /var/lib/kea/kea-leases4.csv. Open the firewall for DHCP on the LAN side only: with firewalld, add the service to the zone that holds the LAN interface (for example sudo firewall-cmd --permanent --zone=internal --add-service=dhcp, then sudo firewall-cmd --reload); with ufw, sudo ufw allow in on enp2s0 to any port 67 proto udp.

Coming from dhcpd? The subnet { range …; option routers …; host … { hardware ethernet …; fixed-address …; } } blocks of dhcpd.conf map directly onto subnet4, pools, option-data and reservations. ISC links migration help from its ISC DHCP page, and Fedora packages ISC’s conversion tool as kea-keama.

dnsmasq for a small network

dnsmasq combines a DHCP server, a DNS cache and a TFTP server. It reads /etc/dnsmasq.conf at startup. Each line is a long command-line option without the leading --. Install with sudo apt install dnsmasq or sudo dnf install dnsmasq, then add:

interface=enp2s0
bind-interfaces
domain=lan
expand-hosts
dhcp-range=192.168.1.100,192.168.1.199,12h
dhcp-option=option:router,192.168.1.1
dhcp-option=option:dns-server,192.168.1.1
dhcp-host=52:54:00:12:34:56,192.168.1.20,nas
dhcp-authoritative

dhcp-host is the reservation: MAC address, IP address, host name. dhcp-authoritative tells dnsmasq it is the only DHCP server on this network; set it only when that is true. With expand-hosts and domain=lan, DHCP clients become resolvable as name.lan through dnsmasq’s DNS side.

dnsmasq --test                      # prints "dnsmasq: syntax check OK."
sudo systemctl enable --now dnsmasq
cat /var/lib/misc/dnsmasq.leases    # current leases (Debian/Ubuntu)
sudo cat /var/lib/dnsmasq/dnsmasq.leases   # Fedora/RHEL

Port 53 clash. dnsmasq also starts a DNS server. If systemd-resolved or another resolver already owns port 53 on the same address, keep bind-interfaces and the interface= line so dnsmasq only binds the LAN interface, or add port=0 to turn its DNS side off. Sharing an Internet connection with dnsmasq is covered in the IP Masquerade HOWTO.

A tiny server with systemd-networkd

For a lab network or a bridge for virtual machines, networkd can serve DHCP itself:

[Match]
Name=enp2s0

[Network]
Address=192.168.50.1/24
DHCPServer=yes

[DHCPServer]
PoolOffset=100
PoolSize=50
EmitDNS=yes
DNS=192.168.50.1

[DHCPServerStaticLease]
MACAddress=52:54:00:12:34:56
Address=192.168.50.20

This hands out 192.168.50.100 to .149, gives the router address (the server itself) automatically, and always gives the listed MAC address .20.

Troubleshooting

Sources