ISC DHCP (Internet Systems Consortium DHCP Server) is the most widely deployed open-source DHCP implementation and provides flexible IP address management for networks of any size. On RHEL 9, the dhcp-server package provides dhcpd, which handles both dynamic leases and static address reservations from a single configuration file. Although ISC announced the end-of-life of ISC DHCP in favour of Kea, it remains available on RHEL 9 and is appropriate for environments that need a well-understood, stable daemon with simple failover capabilities. This tutorial covers installing, configuring, and hardening an ISC DHCP server on RHEL 9.

Prerequisites

  • RHEL 9 server with a static IP on the interface that will serve DHCP (e.g., 192.168.1.1/24 on ens3)
  • Root or sudo access
  • The subnet you intend to serve must be directly attached to the server (or a DHCP relay agent must be in place for remote subnets)
  • No other DHCP server active on the same subnet

Step 1 — Install the DHCP Server

sudo dnf install -y dhcp-server

# Confirm the installed version
dhcpd --version

# The main configuration file location
ls -l /etc/dhcp/dhcpd.conf

Step 2 — Write the Main Configuration File

Edit /etc/dhcp/dhcpd.conf to define global options, the served subnet, the dynamic address range, and default gateway and DNS settings. The example below serves the 192.168.1.0/24 subnet.

# /etc/dhcp/dhcpd.conf

# Global options
option domain-name "example.internal";
option domain-name-servers 192.168.1.1, 8.8.8.8;
default-lease-time 86400;    # 24 hours in seconds
max-lease-time 172800;       # 48 hours

# Authoritative declaration — required to send DHCPNAK for wrong-subnet requests
authoritative;

# Log facility
log-facility local7;

# Subnet declaration
subnet 192.168.1.0 netmask 255.255.255.0 {
    range 192.168.1.100 192.168.1.200;
    option routers 192.168.1.1;
    option broadcast-address 192.168.1.255;
    option subnet-mask 255.255.255.0;
}

Step 3 — Add Static Lease Reservations

Static reservations (fixed addresses) bind a specific MAC address to a permanent IP. They are defined inside the same dhcpd.conf file, outside any subnet block or inside it.

# Append to /etc/dhcp/dhcpd.conf

# Static reservation for a server
host myserver {
    hardware ethernet 52:54:00:ab:cd:ef;
    fixed-address 192.168.1.10;
    option host-name "myserver";
}

# Static reservation for a network printer
host printer01 {
    hardware ethernet 00:1A:2B:3C:4D:5E;
    fixed-address 192.168.1.15;
}

# Validate the configuration syntax before restarting
sudo dhcpd -t -cf /etc/dhcp/dhcpd.conf

Step 4 — Start dhcpd and Configure the Firewall

Enable and start the service, then open UDP port 67 (DHCP server) in firewalld. DHCP uses UDP broadcasts, so no destination IP filtering is needed.

# Specify the interface dhcpd should listen on
# Edit /etc/sysconfig/dhcpd and set DHCPDARGS
echo 'DHCPDARGS=ens3' | sudo tee /etc/sysconfig/dhcpd

# Enable and start the service
sudo systemctl enable --now dhcpd

# Verify the service is active
sudo systemctl status dhcpd

# Open the firewall
sudo firewall-cmd --permanent --add-service=dhcp
sudo firewall-cmd --reload

# Confirm UDP 67 is open
sudo firewall-cmd --list-services

Step 5 — Monitor Active Leases

All dynamically assigned leases are recorded in /var/lib/dhcpd/dhcpd.leases. Each entry shows the IP, MAC address, hostname, and lease start/end times.

# View the leases file
sudo cat /var/lib/dhcpd/dhcpd.leases

# Example lease entry:
# lease 192.168.1.105 {
#   starts 0 2026/05/17 10:00:00;
#   ends   1 2026/05/18 10:00:00;
#   binding state active;
#   hardware ethernet aa:bb:cc:dd:ee:ff;
#   client-hostname "laptop";
# }

# Count active leases
grep -c "binding state active" /var/lib/dhcpd/dhcpd.leases

# Follow dhcpd logs in real time
sudo journalctl -u dhcpd -f

Step 6 — Configure DHCP Failover with a Secondary Server

ISC DHCP supports an active-standby failover pair. The primary and secondary servers share the lease database so that the secondary can take over if the primary fails. Add the following failover peer block to dhcpd.conf on both servers, then reference it in the subnet declaration.

# On the PRIMARY server — add before the subnet block
failover peer "dhcp-failover" {
    primary;
    address 192.168.1.1;
    port 647;
    peer address 192.168.1.2;
    peer port 647;
    max-response-delay 30;
    max-unacked-updates 10;
    load balance max seconds 3;
    mclt 1800;
    split 128;  # 50/50 split of the address pool
}

# On the SECONDARY server — same block, swap primary/secondary roles
failover peer "dhcp-failover" {
    secondary;
    address 192.168.1.2;
    port 647;
    peer address 192.168.1.1;
    peer port 647;
    max-response-delay 30;
    max-unacked-updates 10;
    load balance max seconds 3;
}

# In the subnet block on BOTH servers, reference the failover peer:
subnet 192.168.1.0 netmask 255.255.255.0 {
    pool {
        failover peer "dhcp-failover";
        range 192.168.1.100 192.168.1.200;
    }
    option routers 192.168.1.1;
}

# Open the failover port on both servers
sudo firewall-cmd --permanent --add-port=647/tcp
sudo firewall-cmd --reload

Conclusion

You have installed and fully configured an ISC DHCP server on RHEL 9, including a subnet with dynamic ranges, static MAC-to-IP reservations, firewall rules, lease monitoring, and an active-standby failover pair. The failover configuration ensures that clients can renew leases even if the primary server goes offline, with no manual intervention required. For new deployments, consider evaluating ISC Kea as a modern, API-driven successor to ISC DHCP, but for existing RHEL 9 environments ISC DHCP remains a reliable and well-documented choice.

Next steps: How to Configure Bridge Networking on RHEL 9, How to Set Up a DNS Server with BIND on RHEL 9, and How to Configure DRBD for High-Availability Storage on RHEL 9.