Replacing Ubuntu’s Default DNS with Dnsmasq: Fixing Stale IPs in My Home Network

Stale IPs on a Home Network? Let dnsmasq Clean Up the Mess

If you’ve ever pinged a device that had moved to a new address and the reply came from an old IP, you’ve probably been frustrated by the same stale DNS entries that linger in the resolver cache. On a typical Ubuntu desktop or server, systemd‑resolved is the default DNS stub. It’s great for most use cases, but it can keep outdated records for a long time, especially when your router’s DHCP server changes leases frequently. The result? Your own machine keeps trying to resolve a dead address until the cache finally expires.

The fix is simple: replace the stub resolver with a lightweight local caching DNS server that you control. dnsmasq is a proven, battle‑tested choice. It can act as a DHCP server, a DNS forwarder, and a DNS cache all in one. In this post I’ll walk through installing dnsmasq on Ubuntu 24.04, configuring it to forward to your upstream nameservers, disabling systemd‑resolved, and a few tricks to keep the cache fresh and secure.


Why dnsmasq over systemd‑resolved?

Feature systemd‑resolved dnsmasq
DNS cache TTL 1 h (default) configurable per‑record
DHCP server No Yes
Local domain handling Limited Full support
Cache invalidation Manual systemd-resolve --flush-caches Automatic on lease change
Security Uses systemd’s sandbox Runs as dnsmasq user, minimal privileges

systemd‑resolved is fine for most desktop users, but when you’re running a home lab or a small server that relies on local hostnames, the stale cache can break services. dnsmasq gives you fine‑grained control over TTLs and lets you drop the stale entries as soon as the DHCP lease changes.


Step 1 – Install dnsmasq

sudo apt update
sudo apt install dnsmasq

The package ships with a default configuration in /etc/dnsmasq.conf. It’s intentionally minimal; we’ll override the parts we need.


Step 2 – Disable systemd‑resolved

systemd‑resolved listens on /run/systemd/resolve/stub-resolv.conf and on the loopback interface. To avoid conflicts, stop and mask it:

sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved
sudo systemctl mask systemd-resolved

Next, edit /etc/resolv.conf to point to the local dnsmasq instance:

sudo nano /etc/resolv.conf

Replace its contents with:

nameserver 127.0.0.1

If you’re on a system that still uses resolvconf, you can also create a hook to keep the file in sync, but for a single‑node setup the static file is fine.


Step 3 – Configure dnsmasq

Open /etc/dnsmasq.conf for editing:

sudo nano /etc/dnsmasq.conf

Add or uncomment the following lines:

# Forward all queries to the router’s DNS
server=192.168.1.1

# Use the router’s DHCP server for local network
dhcp-range=192.168.1.100,192.168.1.200,12h

# Short TTL for local names to avoid stale entries
local-service
local=/home/

Explanation

  • server= tells dnsmasq where to forward queries it can’t resolve locally. Replace 192.168.1.1 with your router’s IP.
  • dhcp-range= gives dnsmasq a DHCP pool. If you already use your router for DHCP, comment this out. If you want dnsmasq to handle DHCP, keep it.
  • local-service limits DNS queries to the local network, which is a small security hardening step.
  • local=/home/ tells dnsmasq that any name ending in .home. is local. You can use any domain you prefer.

If you’re only using dnsmasq as a cache, you can leave the DHCP section out entirely. In that case, add:

no-dhcp-interface=

to prevent it from listening on any interface for DHCP.


Step 4 – Restart and Test

sudo systemctl restart dnsmasq

Check the status:

sudo systemctl status dnsmasq

Now test resolution:

dig @127.0.0.1 mydevice.home

If you see a response from the router’s DNS, you’re good. To verify that stale entries are gone, try pinging a device that just changed IP:

ping -c 3 mydevice.home

The reply should come from the new address immediately.


Step 5 – Fine‑Tuning TTLs

dnsmasq lets you set TTLs per‑record. For example, to force a 30‑second TTL for all local names:

local=/home/
local-ttl=30

If you need longer TTLs for external domains, add:

server=8.8.8.8
server=8.8.4.4

and keep the default TTL for those.


Security Considerations

  1. Run dnsmasq as a non‑root user – The package already does this (dnsmasq user). If you’re running it manually, use --user=dnsmasq --group=dnsmasq.
  2. Limit query scopelocal-service and listen-address=127.0.0.1 prevent external hosts from querying your cache.
  3. Disable DNSSEC validationdnsmasq does not validate DNSSEC by default. If you need validation, install dnssec-root and add trust-anchor=... lines, but that adds complexity.
  4. Keep the package updateddnsmasq is actively maintained. Ubuntu’s package is usually up to date, but you can also install from the upstream repo on GitHub if you need the latest features.

Troubleshooting

Symptom Likely Cause Fix
dig @127.0.0.1 returns SERVFAIL dnsmasq not listening sudo systemctl restart dnsmasq
Stale IP persists systemd-resolved still active Verify systemctl status systemd-resolved
No resolution for external domains Wrong upstream server Check server= lines
DHCP conflicts Two DHCP servers running Disable DHCP in dnsmasq or router

Use journalctl -u dnsmasq for detailed logs. If you see “Failed to bind to 127.0.0.1:53”, another process is already listening on port 53. That’s usually systemd-resolved. Make sure it’s fully stopped.


When to Keep systemd‑resolved

If you’re on a multi‑node network where the router’s DNS is authoritative and you rarely change IPs, the default resolver is fine. dnsmasq shines when:

  • You run a local server that relies on hostnames that change (e.g., a Raspberry Pi that reboots).
  • You want to host a local domain (e.g., *.home) without touching the router.
  • You need to serve DHCP and DNS from a single machine.

Quick Reference

# Install
sudo apt install dnsmasq

# Disable systemd-resolved
sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved
sudo systemctl mask systemd-resolved

# Point resolv.conf
echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf

# Basic dnsmasq config
cat <<EOF | sudo tee /etc/dnsmasq.conf
server=192.168.1.1
local=/home/
local-ttl=30
EOF

# Restart
sudo systemctl restart dnsmasq

Tags

dnsmasq, dns, systemd-resolved, ubuntu, networking


See also