A Pi-hole DHCP server setup guide comes down to four moves, in this order: pin the Pi-hole to a static IP configured on the host itself, switch off DHCP on your router, set the pool, gateway and lease time under Settings > DHCP, then enable it. Clients move over as their leases renew.
The order matters more than any setting. With DHCP active, FTL writes dhcp-authoritative into its generated dnsmasq config (FTL source), a flag the dnsmasq man page says “should be set when dnsmasq is definitely the only DHCP server on a network.” Two DHCP servers on one broadcast domain is how a whole household loses connectivity on a Tuesday night.
Should Pi-hole run DHCP on your network?
Only when the router forces your hand. If your router lets you set the DNS server it hands out (DHCP option 6), point that at Pi-hole and stop. Pi-hole’s DHCP server earns its place when an ISP gateway locks the DNS field, or when the router hands out itself and forwards everything, so Pi-hole logs every query as the router’s IP.
The project’s DHCP FAQ names the same reasons, plus named reservations that turn MAC addresses into hostnames in the query log. The post-install docs add the rule that governs everything below: “just be sure to disable DHCP on your router first.”
The cost: Pi-hole becomes a single point of failure for addressing, not just names. If its SD card dies, new devices get no address at all. If your edge is pfSense or OPNsense, its own DHCP server can hand out the Pi-hole as DNS instead; the trade-offs are in Pi-hole vs pfSense pfBlockerNG.
Plan the addresses before touching anything
The worked example is a flat home LAN:
| Item | Example value |
|---|---|
| Subnet | 192.168.1.0/24 |
| Gateway (router) | 192.168.1.1 |
| Pi-hole host, static on the host | 192.168.1.53 |
| Reservations | 192.168.1.10 to 192.168.1.99 |
| Dynamic pool | 192.168.1.100 to 192.168.1.199 |
| Lease time | 24h |
While the router’s DHCP still runs, export its pool, lease time and every reservation. Printers, the NAS, cameras and anything with a port forward pinned to an address must come across as Pi-hole reservations, or they renumber and break silently.
A day before cutover, drop the router’s lease time to one hour so clients renew soon after the switch. Keep a laptop and an Ethernet cable ready to take a static address such as 192.168.1.250/24, so a failed cutover can’t lock you out of the router.
Step 1: give the Pi-hole host a real static IP
If you followed the Raspberry Pi install guide, Pi-hole may be pinned by a reservation on the router. That breaks the moment the router’s DHCP goes off, because the Pi-hole would need to lease its own address from itself. Set the address on the host. With NetworkManager:
nmcli con show
sudo nmcli con mod "Wired connection 1" ipv4.method manual ipv4.addresses 192.168.1.53/24 ipv4.gateway 192.168.1.1 ipv4.dns 127.0.0.1
sudo nmcli con up "Wired connection 1"
Substitute whatever connection name nmcli con show reports. dnsmasq needs an interface address inside the subnet it serves. If the host runs ufw or nftables, allow inbound UDP 67; per RFC 2131, servers listen on port 67 and clients on 68.
Step 2: turn off DHCP on the router
Disable the router’s DHCPv4 server outright; a shrunken pool is still a second server. Mesh kits, ISP modems in router mode and old routers reused as access points typically run DHCP too unless set to bridge or AP mode. Check what is still answering:
sudo pihole-FTL dhcp-discover
sudo nmap --script broadcast-dhcp-discover
dhcp-discover, in FTL since v5.3, scans every interface for DHCP servers. Nmap’s broadcast-dhcp-discover uses a fixed MAC so it doesn’t consume a pool address. Both should find nothing before you enable Pi-hole. RFC 2131 lets a client choose among multiple offers by its own criteria, so a stray server hands some devices the wrong DNS and gateway, unpredictably.
Step 3: enable Pi-hole’s DHCP server
In the web interface, open Settings > DHCP, tick the DHCP server checkbox, and fill in range, router, netmask and lease time. From the CLI, set active last so FTL never starts with an empty range:
sudo pihole-FTL --config dhcp.start "192.168.1.100"
sudo pihole-FTL --config dhcp.end "192.168.1.199"
sudo pihole-FTL --config dhcp.router "192.168.1.1"
sudo pihole-FTL --config dhcp.netmask "255.255.255.0"
sudo pihole-FTL --config dhcp.leaseTime "24h"
sudo pihole-FTL --config dhcp.active true
From the FTL configuration reference:
dhcp.routeris the gateway handed to clients. Put the Pi-hole’s address here and every client loses its route off the LAN.dhcp.netmaskleft empty is auto-discovered from the interface.dhcp.leaseTimeleft empty means one hour for IPv4. Lease length is your outage budget: clients renew at T1, half the lease, so if the Pi-hole dies a 24h lease leaves each device 12 to 24 hours of slack, and a 1h lease leaves 30 to 60 minutes.dhcp.rapidCommitenables the two-message exchange of RFC 4039, which that RFC says MUST only be used when the server is alone on the subnet or every server can address every client. Leave it off.dhcp.multiDNSadvertises the Pi-hole several times, for devices that append their own proprietary resolvers.
FTL then regenerates /etc/pihole/dnsmasq.conf with dhcp-authoritative, dhcp-leasefile=/etc/pihole/dhcp.leases, dhcp-range=192.168.1.100,192.168.1.199,255.255.255.0,24h and dhcp-option=option:router,192.168.1.1, plus domain=lan from dns.domain.name, so leased hosts resolve as nas.lan. The reference says that domain is never forwarded upstream unless a reverse server is configured.
Step 4: add reservations
Static leases live in dhcp.hosts, one MAC,IP,hostname,leasetime string per device, written out as dhcp-host= lines:
sudo pihole-FTL --config dhcp.hosts '["00:20:e0:3b:13:af,192.168.1.20,nas,24h","00:20:e0:ab:cd:ef,192.168.1.21,printer,24h"]'
The CLI sets the whole array, so re-send existing entries when adding one; the same list is editable under Settings > DHCP. Keep reservations outside the dynamic pool. The payoff is a query log showing printer instead of an IP.
dhcp.ignoreUnknownClients writes dhcp-ignore=tag:!known, serving only listed MACs. Good for a LAN of cameras and plugs; miserable with phones using randomized private Wi-Fi addresses.
Step 5: move clients over and verify
Clients hold their router lease until renewal. Force it where you can, and power-cycle IoT devices:
ipconfig /release && ipconfig /renew # Windows
sudo ipconfig set en0 DHCP # macOS
sudo nmcli con up "Wired connection 1" # Linux, NetworkManager
On the Pi-hole:
sudo pihole-FTL dhcp-discover
sudo tail -F /var/log/pihole/pihole.log | grep -E 'DHCP(DISCOVER|OFFER|REQUEST|ACK)'
sudo cat /etc/pihole/dhcp.leases
dhcp-discover should now list exactly one responder, 192.168.1.53. Enable dhcp.logging during cutover for option-level detail, then disable it. On a client:
ipconfig /all # DHCP Server and DNS Servers = 192.168.1.53
nmcli dev show | grep -E 'IP4.(ADDRESS|GATEWAY|DNS)' # Linux
dig @192.168.1.53 nas.lan +short
dig @192.168.1.53 -x 192.168.1.20 +short
The dig pair proves the lease-to-DNS link: the forward name returns the reserved address, the reverse lookup returns the name. If the query log still shows one client IP, or blocking looks partial after every device has renewed, work through why Pi-hole is not blocking ads.
What changes with IPv6 and VLANs?
Both break the single-subnet design of Pi-hole’s DHCP page. dhcp.ipv6 adds SLAAC and stateless DHCPv6, not stateful leases, and a second VLAN needs a tagged subinterface or a router relay plus hand-written dnsmasq ranges, because the [dhcp] section defines exactly one range.
With dhcp.ipv6 true, FTL writes dhcp-range=::,constructor:<interface>,ra-names,ra-stateless,64. Per the dnsmasq man page, ra-stateless sends Router Advertisements with the O and A bits set: clients self-assign via SLAAC and fetch DNS over stateless DHCPv6. Your router keeps sending its own RAs, and if those advertise the router as DNS, dual-stack clients resolve around Pi-hole. Fix the router’s RA DNS setting first.
For a relayed IoT VLAN, enable misc.etc_dnsmasq_d, as suggested in a Pi-hole forum thread on v6 VLANs, and add a range:
# /etc/dnsmasq.d/10-vlan30.conf
dhcp-range=set:iot,192.168.30.100,192.168.30.199,255.255.255.0,24h
dhcp-option=tag:iot,option:router,192.168.30.1
The netmask is mandatory there, since dnsmasq derives it only for directly connected networks. Relayed clients also query from a subnet Pi-hole isn’t on, which the default dns.listeningMode of LOCAL drops. And a router that can relay DHCP can almost always set option 6 per VLAN, which is the better design. On MikroTik hardware, see RouterOS DHCP server setup for VLANs.
FAQ
can pi-hole and my router both run dhcp at the same time
No. Both servers answer every broadcast DISCOVER, and RFC 2131 leaves the choice of offer to the client, so devices land on whichever server they happen to pick. Some get the router as DNS, some get Pi-hole, and Pi-hole’s dnsmasq runs in authoritative mode, which assumes it is alone. Disable one server completely.
what happens if pi-hole goes down while it runs dhcp
Devices with a current lease keep their addresses until it expires, retrying renewal from the halfway point. New devices get no address, and since Pi-hole is usually also the DNS server, name resolution fails everywhere at once. Longer leases buy repair time. A second Pi-hole configured for failover is the real fix.
how do i switch back to my router’s dhcp server
Run sudo pihole-FTL --config dhcp.active false first, then re-enable DHCP on the router, so the two never overlap. Clients migrate as they renew; release and renew manually to speed it up. If you can’t reach the router’s admin page, set a cabled laptop to a static address in the subnet and connect directly.
does pi-hole dhcp work in docker
Yes, with extra plumbing. The docker-pi-hole README says the container needs the NET_ADMIN capability and a UDP 67 mapping. DHCP broadcasts cannot cross Docker’s bridge, so the Pi-hole Docker docs offer host networking, a macvlan network giving the container its own LAN address, or bridge mode plus a DHCP relay.
Related across the network
- How to Set Up Pi-hole in Docker Compose and Keep It Running — dockerhomelab.com
- Docker Macvlan in Compose: Give Containers a LAN IP — dockerhomelab.com