How to Set Up a DHCP Server on Fedora

Install dnsmasq on Fedora using dnf, configure the subnet in /etc/dnsmasq.conf, and enable the service to start a DHCP server.

You need to hand out IP addresses

You plug a new laptop into your home network. It expects an IP address. Your Fedora machine sits there with a static IP, but nothing else gets one. You open the terminal, run dnf install dhcp-server, and get a No match for argument: dhcp-server error. Fedora does not ship a monolithic DHCP daemon by default. You have to pick the right tool for your network size, point it at the correct interface, and start it up.

How DHCP actually works on your network

DHCP is a four-step handshake. A client broadcasts a discovery packet to 255.255.255.255. A server hears it, checks its address pool, and offers an IP. The client requests that IP. The server acknowledges it and hands back a subnet mask, a default gateway, and DNS servers. The client configures its interface and joins the network.

On Fedora, you are usually running NetworkManager on the host itself. NetworkManager handles the host's own connection. It does not hand out addresses to other machines. You need a separate daemon listening on a specific interface, usually a bridged or routed Ethernet port. The daemon maintains a lease database, tracks which MAC addresses got which IPs, and renews them before they expire. Think of it like a front desk at a hotel. Guests walk in, the clerk checks the registry, hands them a key for a set number of days, and tracks when they check out so the room can be reassigned.

Install and configure dnsmasq

For most home labs, small offices, and virtual networks, dnsmasq is the right choice. It is lightweight, handles both DNS and DHCP, and requires minimal configuration. Install it from the default repositories.

sudo dnf install -y dnsmasq
# Install the daemon and its dependencies without prompting for confirmation
sudo systemctl enable --now dnsmasq
# Start the service immediately and ensure it boots with the system

The default configuration lives in /etc/dnsmasq.conf. Files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Edit /etc/. Never edit /usr/lib/. Open the configuration file and define your subnet, gateway, and lease duration.

# Listen only on the interface that connects to your clients
# Replace eth1 with your actual interface name
interface=eth1

# Define the IP pool, gateway, and lease time in hours
dhcp-range=192.168.1.50,192.168.1.150,12h

# Hand out the router address so clients can reach the internet
dhcp-option=3,192.168.1.1

# Provide DNS servers. Use your router or public resolvers.
dhcp-option=6,192.168.1.1,8.8.8.8

# Disable DNS forwarding if you only want DHCP functionality
port=0

Save the file and restart the daemon. The service reads the configuration on startup. It does not hot-reload changes.

sudo systemctl restart dnsmasq
# Reload the daemon so it picks up the new subnet and interface settings
sudo systemctl status dnsmasq
# Verify the service is active and check the last few log lines

Check the status output before moving on. If the service fails to start, the configuration contains a syntax error or the interface name is wrong. Run journalctl -xeu dnsmasq to see the exact failure reason. The x flag adds explanatory text and the e flag jumps to the end. Most sysadmins type journalctl -xeu <unit> muscle-memory style.

Restart the service after every config change. Do not guess why it failed.

Open the firewall and check SELinux

DHCP uses UDP ports 67 and 68. Fedora's default firewall blocks incoming traffic on those ports. You must allow DHCP traffic through the zone that matches your server interface.

sudo firewall-cmd --permanent --add-service=dhcp
# Add the DHCP service to the persistent firewall rules
sudo firewall-cmd --reload
# Apply the persistent rules to the running firewall immediately

Always run firewall-cmd --reload after every rule change. Otherwise the runtime config and the persistent config diverge. You will spend hours wondering why clients cannot get an address.

SELinux runs in enforcing mode by default on Fedora. dnsmasq has a predefined policy that allows it to bind to network ports and write its lease database. You do not need to disable SELinux. If you see denials, they usually point to a misconfigured file context or a custom script calling the daemon. Check the audit logs before touching SELinux settings.

sudo ausearch -m avc -ts recent | grep dnsmasq
# Search the audit log for recent SELinux access vector cache denials

If the command returns nothing, SELinux is not blocking the service. The issue is elsewhere. Trust the package manager. Manual file edits drift, snapshots stay.

Verify the leases are working

A running daemon does not mean clients are getting addresses. Check the lease database to confirm the handshake completed. dnsmasq stores leases in /var/lib/dnsmasq/dnsmasq.leases by default.

sudo cat /var/lib/dnsmasq/dnsmasq.leases
# Display the current lease table with timestamps, MACs, IPs, and hostnames

The output shows four columns. The first is the lease expiration time in Unix epoch format. The second is the client MAC address. The third is the assigned IP. The fourth is the hostname the client reported during the handshake. If the file is empty, the client never reached the server.

Test from a client machine. Run ip addr or ipconfig to see if it received an address in your defined range. Ping the gateway. If the client gets a 169.254.x.x address, it fell back to link-local addressing because the DHCP request timed out. That means the server is not hearing the broadcast. Verify the interface name in the config. Verify the firewall rules. Verify the cable or bridge is active.

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

Common pitfalls and what the error looks like

The most frequent issue is binding to the wrong interface. dnsmasq will silently ignore requests on interfaces it is not listening on. If you see dnsmasq: failed to create listening socket for port 53: Address already in use, another service is occupying the DNS port. Set port=0 in the config if you only need DHCP.

Firewall misconfigurations are the second most common blocker. Clients broadcast on UDP 68. The server replies on UDP 67. If the firewall drops UDP 67, the handshake breaks at step two. The client will eventually give up and assign itself a link-local address. You will see DHCPREQUEST packets in tcpdump but no DHCPACK.

SELinux denials appear in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux. The summary usually tells you exactly which file or port is blocked. Fix the context or add the correct boolean. Do not set SELinux to permissive as a workaround. You will hide the real problem and create a security gap.

Lease database permissions can also break the service. The daemon runs as the dnsmasq user. If you manually created the lease directory as root, the daemon cannot write to it. The service will start but fail to track leases. You will see dnsmasq: failed to open lease file /var/lib/dnsmasq/dnsmasq.leases: Permission denied in the logs. Fix the ownership with sudo chown dnsmasq:dnsmasq /var/lib/dnsmasq/.

Reboot before you debug. Half the time the symptom is gone.

When to use this versus other tools

Use dnsmasq when you want a lightweight daemon that handles DHCP and basic DNS for a home lab, virtual network, or small office. Use isc-dhcp-server when you need enterprise features like DHCP failover, complex option overrides, or integration with centralized logging systems. Use NetworkManager's built-in connection sharing when you are temporarily tethering a single laptop to a phone or another device. Stay on the upstream dnsmasq configuration if you only deviate from the defaults occasionally.

Where to go next