How to Set Up a DHCP Server (dhcpd or dnsmasq) on Fedora

Install dnsmasq or dhcpd on Fedora, configure the service, and enable it to automatically assign IP addresses to network devices.

You wired up a lab network and the clients are stuck

You connected a switch to your Fedora machine's second network interface to create an isolated test environment. You plug in a laptop, and the laptop gets a 169.254.x.x address. That address means the laptop gave up. It broadcast a request for an IP, heard nothing, and assigned itself a link-local address as a fallback. Your Fedora box has the interface and the traffic, but it isn't answering. You need a DHCP server.

How DHCP actually works

DHCP stands for Dynamic Host Configuration Protocol. It is the mechanism that assigns IP addresses, gateways, and DNS servers to devices on a network. The protocol follows a four-step handshake known as DORA.

The client sends a Discover broadcast. Any DHCP server on the segment hears this. The server responds with an Offer, proposing an IP address and lease time. The client replies with a Request, accepting the offer. The server sends an Acknowledge to confirm the lease. The client then configures its interface.

Fedora does not run a DHCP server by default. The default network stack uses NetworkManager, which acts as a DHCP client. NetworkManager asks for addresses. It does not give them out. You must install a daemon to handle the server role. The daemon listens on UDP port 67 for incoming requests and manages a pool of available addresses.

Install and configure dnsmasq

dnsmasq is a lightweight service that combines DHCP and DNS. It is the standard choice for home labs, routers, and small networks where you want a simple configuration file and low resource usage.

Here's how to install dnsmasq and enable the service.

sudo dnf install dnsmasq -y
# -y skips the confirmation prompt. Use this only when you trust the package list.
sudo systemctl enable --now dnsmasq
# enable adds the service to boot targets. --now starts it immediately.

The package installs the binary and a default configuration file. Fedora follows the convention of keeping user modifications in /etc/ and shipping package defaults in /usr/lib/. Edit /etc/dnsmasq.conf. Never edit files in /usr/lib/. Those files get overwritten on package updates.

Here's how to configure dnsmasq to serve a specific interface and IP range.

# /etc/dnsmasq.conf
interface=eth1
# Bind dnsmasq to eth1. It will ignore other interfaces.
dhcp-range=192.168.50.100,192.168.50.200,255.255.255.0,12h
# Define the pool of IPs to hand out and the lease duration.
dhcp-option=3,192.168.50.1
# Option 3 is the router/gateway. Tell clients where to send traffic.
dhcp-option=6,192.168.50.1,8.8.8.8
# Option 6 is DNS servers. Provide local and public resolvers.

The dhcp-range line takes four arguments. The first two are the start and end of the IP pool. The third is the netmask. The fourth is the lease time. A lease of 12h means clients must renew every twelve hours. Shorter leases help when devices move frequently. Longer leases reduce broadcast traffic.

Restart the service after editing the configuration.

sudo systemctl restart dnsmasq
# Restart applies the new configuration. The service reloads the config file.

Configure the firewall

Fedora's firewall blocks incoming traffic by default. DHCP uses UDP ports 67 and 68. You must open these ports for the server to hear requests.

Here's how to add the DHCP service to the firewall and make the change persistent.

sudo firewall-cmd --permanent --add-service=dhcp
# --permanent writes to the persistent config. This survives reboots.
sudo firewall-cmd --reload
# Reload applies the permanent config to the running firewall. Always reload after changes.

The --permanent flag updates the configuration file on disk. The --reload flag merges that file into the active runtime configuration. If you skip the reload, the runtime and persistent configs diverge. The firewall will block traffic until you reboot. Run firewall-cmd --reload after every rule change.

Install and configure dhcpd

dhcpd is the ISC DHCP server. It is a full-featured daemon designed for enterprise networks. It supports failover, complex option profiles, and strict access control. The configuration syntax is more verbose than dnsmasq.

Here's how to install the ISC DHCP server and enable the service.

sudo dnf install dhcp-server -y
sudo systemctl enable --now dhcpd
# dhcpd checks the configuration file on start. It will not start if the config is invalid.

The service will likely fail immediately because the default configuration file is empty or contains only comments. dhcpd refuses to start without a valid subnet declaration. This is a safety feature. A misconfigured DHCP server can disrupt an entire network.

Here's how to write a minimal subnet configuration for dhcpd.

# /etc/dhcp/dhcpd.conf
subnet 192.168.50.0 netmask 255.255.255.0 {
  range 192.168.50.100 192.168.50.200;
  # Define the IP pool for this subnet.
  option routers 192.168.50.1;
  # Tell clients where the gateway is.
  option domain-name-servers 192.168.50.1, 8.8.8.8;
  # Provide DNS servers.
  default-lease-time 43200;
  # Default lease time in seconds. 43200 is 12 hours.
  max-lease-time 86400;
  # Maximum lease time clients can request.
}

The configuration uses a block structure. Each subnet block defines a network segment. The range statement sets the pool. Options are passed to clients using the option keyword. Save the file and restart the service.

sudo systemctl restart dhcpd
# Restart triggers a config check. Check journalctl if the service fails.

Verify the server is handing out addresses

Check the service status and the logs to confirm the server is running and processing requests.

Here's how to check the service state and view recent log entries with explanatory context.

systemctl status dnsmasq
# Check state and recent logs. Always check status before restart.
journalctl -xeu dnsmasq
# -x adds explanatory text. -e jumps to end. -u filters by unit.

The journalctl -xeu command is the standard way to debug services. The x flag adds explanatory text from systemd. The e flag jumps to the end of the journal. The u flag filters by unit name. Most sysadmins type this muscle-memory style.

Look for lines containing DHCPACK. This indicates the server successfully acknowledged a request. If you see DHCPNAK, the server rejected the request, usually due to a configuration mismatch or lease conflict.

Test with a client device. Connect a laptop to the network interface. Renew the IP address on the client. On Windows, run ipconfig /renew. On Linux, run sudo dhclient -r followed by sudo dhclient. On macOS, use the Network preferences or sudo ipconfig renew en0.

Check the lease file to see active leases. dnsmasq stores leases in /var/lib/dnsmasq/dnsmasq.leases. dhcpd stores leases in /var/lib/dhcpd/dhcpd.leases.

cat /var/lib/dnsmasq/dnsmasq.leases
# View active leases. Each line shows timestamp, MAC, IP, hostname, and lease expiry.

Reboot the client if the lease file looks correct but the client still has the wrong IP. The server won't fix a stale lease on the client side.

Common pitfalls and error messages

DHCP servers fail silently if the firewall blocks traffic. The service runs, but clients never hear the offer. Check the firewall first.

If dhcpd fails to start, you will see an error in the journal.

dhcpd[1234]: exiting because of configuration errors.

This error means the configuration file has a syntax error or is missing a subnet declaration. dhcpd validates the entire file before binding to any socket. Fix the config and restart.

If dnsmasq fails to bind, you might see this error.

dnsmasq[1234]: failed to create listening socket for port 67: Address already in use

Another process is using port 67. This often happens if you installed dnsmasq but NetworkManager's internal DHCP helper is also active on the same interface. Check for conflicting services.

sudo ss -ulnp | grep :67
# List UDP sockets bound to port 67. Identify the conflicting process.

SELinux denials can block the server from writing lease files or binding to ports. Check the SELinux log before disabling enforcement.

journalctl -t setroubleshoot
# SELinux denials appear here with a one-line summary. Read those before disabling SELinux.

Run journalctl -xe first. Read the actual error before guessing.

When to use dnsmasq versus dhcpd

Use dnsmasq when you need a lightweight server for a home lab, router, or small office network. Use dhcpd when you manage a large enterprise network with failover requirements or complex option profiles. Use NetworkManager's ad-hoc capabilities when you need a temporary DHCP server for a single test without installing extra packages. Use systemd-networkd when you prefer declarative network configuration and want DHCP functionality integrated into the network manager.

Stay on dnsmasq if you only deviate from the defaults occasionally. Switch to dhcpd when your network policy requires granular control over lease lifetimes and option codes.

Where to go next

Trust the package manager. Manual file edits drift, snapshots stay. Run dnf upgrade --refresh weekly to keep your server secure. dnf system-upgrade is for crossing major Fedora releases. They are different commands. Don't conflate them.