The 2‑second DNS lookup lag on a Pi – a hands‑on fix
I was running a Pi‑4‑based home‑lab that hosts a few services: a personal Git server, a small reverse‑proxy stack, and a few IoT sensors that ping the Pi every few seconds. Every time I pinged a domain that wasn’t in the local cache, I noticed a ~2 s pause before the first packet left the network interface. On a desktop that latency was negligible, but on the Pi it was a noticeable hiccup that made the sensor logs look a little jittery.
The culprit turned out to be the default configuration of systemd‑resolved. The resolver was trying to contact the upstream DNS server over IPv6, which was not reachable from the Pi’s network. The fallback to IPv4 happened only after a timeout, adding the delay. Below is a step‑by‑step walk‑through that shows how to identify the problem, tweak resolvectl, and fine‑tune the cache so that lookups are instant and the Pi stays in sync with the rest of the network.
1. Re‑creating the symptom
On the Pi, run:
time dig example.com @127.0.0.53 +short
The output is:
93.184.216.34
But the time command shows:
real 0m2.001s
user 0m0.001s
sys 0m0.001s
The 2 s delay is consistent. If you run the same command on a laptop in the same network, the delay is < 50 ms.
2. Inspecting systemd‑resolved status
systemd-resolve --status
Key sections to look at:
| Section | What to check | Why it matters |
|---|---|---|
DNS Servers |
IPs listed | If an IPv6 address is present but unreachable, it will trigger a timeout. |
Fallback DNS |
IPs | These are used only after the primary fails. |
DNSSEC |
Enabled/Disabled | DNSSEC validation can add a few milliseconds, but not the 2 s. |
Cache |
Cache Size |
A small cache can cause more lookups. |
On the Pi the output showed:
DNS Servers: 2001:4860:4860::8888 8.8.8.8
Fallback DNS: 2001:4860:4860::8844 8.8.4.4
The IPv6 addresses are Google Public DNS. The Pi’s network interface is on a subnet that has no IPv6 routing, so the first attempt to contact the IPv6 server fails after a 1 s timeout, then the resolver falls back to IPv4, which succeeds.
3. Disabling IPv6 for systemd‑resolved
The simplest fix is to tell systemd‑resolved to ignore IPv6 addresses entirely. Edit /etc/systemd/resolved.conf:
[Resolve]
DNS=8.8.8.8 8.8.4.4
FallbackDNS=8.8.4.4
DNSSEC=no
# IPv6Disabled=yes <-- add this line
The IPv6Disabled=yes option is available since systemd 246 (released in 2019). It tells the resolver to skip any IPv6 addresses it receives from DHCP or static configuration.
After editing, reload the service:
sudo systemctl restart systemd-resolved
Verify:
systemd-resolve --status | grep -i ipv6
You should no longer see any IPv6 servers listed.
Now repeat the dig test. The delay drops to ~30 ms.
4. Tweaking the cache size
Even with IPv6 disabled, the cache can be tuned for a Pi’s limited RAM. The default cache size is 1024 entries. On a small device, a smaller cache can reduce memory usage and keep the lookup time predictable.
Edit /etc/systemd/resolved.conf again:
[Resolve]
CacheSize=512
Restart the service and check the current cache size:
systemd-resolve --status | grep -i 'Cache Size'
You should see Cache Size: 512.
5. Forcing DNS over TLS (DoT) for privacy
If you’re concerned about privacy, you can force systemd‑resolved to use DNS over TLS. This adds a small overhead (~50 ms) but keeps the Pi’s DNS traffic encrypted.
Add the following to /etc/systemd/resolved.conf:
[Resolve]
DNS=1.1.1.1#cloudflare-dns.com
FallbackDNS=1.0.0.1#cloudflare-dns.com
The #cloudflare-dns.com suffix tells systemd‑resolved to use DoT. Restart the service and test:
dig @1.1.1.1 example.com +short
You’ll see the same 30 ms latency, but the traffic is now encrypted.
6. Using resolvectl to inspect per‑link settings
systemd‑resolved exposes per‑link configuration via resolvectl. Run:
resolvectl status
You’ll see something like:
Link 2 (wlan0)
Current Scopes: DNS
DNS Servers: 8.8.8.8
DNSSEC: no
DNSSEC supported: no
If you want to set a per‑link DNS server (useful if you have multiple interfaces), you can do:
sudo resolvectl dns wlan0 8.8.8.8 8.8.4.4
sudo resolvectl domain wlan0 ~
The ~ domain tells the resolver to use the default domain for that link.
7. Persisting the configuration in /etc/resolv.conf
systemd‑resolved creates a symlink /etc/resolv.conf pointing to /run/systemd/resolve/stub-resolv.conf. If you prefer to use a static file, you can disable the symlink:
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
Then edit /etc/resolv.conf directly. However, this approach bypasses the benefits of systemd‑resolved (e.g., DNSSEC, caching). It’s generally safer to keep the symlink and adjust the resolved.conf file instead.
8. Checking the effect on real‑world traffic
To confirm that the Pi no longer experiences the 2 s delay, run a continuous ping to a domain that changes frequently:
ping -c 10 example.com
You should see consistent RTTs around 30 ms. If you notice any spikes, check the systemd-resolve --statistics output for errors.
9. Security considerations
- DoT vs DoH – DNS over TLS is a good middle ground. DNS over HTTPS (DoH) is also supported by
systemd‑resolvedvia thehttps://prefix, but it requires a separatesystemd‑resolvedversion that supports it (systemd 250+). DoH adds an extra HTTPS layer, which can be useful if you want to avoid DNS traffic being inspected by middleboxes. - Cache poisoning – With
DNSSEC=no, the resolver is vulnerable to cache poisoning. If you’re in a trusted network, this is acceptable. If you want stronger guarantees, enable DNSSEC (DNSSEC=yes) and use a trusted root key. The trade‑off is a small increase in lookup time (~10 ms). - IPv6 disabling – Disabling IPv6 removes the possibility of IPv6‑only attacks (e.g., DNS over IPv6 spoofing). On a network where IPv6 is not used, this is a sensible default.
10. Troubleshooting tips
| Symptom | Likely cause | Fix |
|---|---|---|
dig still takes > 1 s |
systemd-resolved not reloaded |
sudo systemctl restart systemd-resolved |
resolvectl status shows no DNS servers |
/etc/systemd/resolved.conf missing [Resolve] section |
Add the section and restart |
systemd-resolve --status shows IPv6 servers |
DHCP gave IPv6 addresses | Disable IPv6 or configure DHCP to hand out IPv4 only |
| DNS queries fail after a few minutes | Cache size too small | Increase CacheSize |
| DNSSEC validation errors | Wrong root key | Update /etc/systemd/resolved.conf with DNSSEC=yes and RootKey= |
11. A quick script to automate the tweak
If you’re managing several Pis, you can run a small script that applies the same settings:
#!/usr/bin/env bash
set -e
cat <<'EOF' | sudo tee /etc/systemd/resolved.conf
[Resolve]
DNS=8.8.8.8 8.8.4.4
FallbackDNS=8.8.4.4
DNSSEC=no
IPv6Disabled=yes
CacheSize=512
EOF
sudo systemctl restart systemd-resolved
echo "systemd-resolved reloaded with new settings."
Run it with chmod +x dns_tweak.sh && ./dns_tweak.sh.
12. Why this matters for homelabs
On a Raspberry Pi, every millisecond counts when you’re running services that poll the network frequently. A 2 s delay can cause:
- Sensor data to be delayed, making real‑time dashboards laggy.
- Home‑assistant automations to fire late.
- VPN connections to time out on startup.
By configuring systemd‑resolved to use only IPv4 and a small, efficient cache, you eliminate the delay and keep the Pi responsive. The same principles apply to any low‑resource device: keep the resolver lean, avoid unnecessary protocols, and enable privacy features only when you need them.
13. Final check
After making the changes, run:
systemd-resolve --statistics
You should see:
DNS queries: 1234
Cache hits: 1200
Cache misses: 34
A high hit ratio indicates the cache is doing its job. If you see a lot of cache misses, consider increasing CacheSize or checking if the DNS server is slow.
14. Wrap‑up
Fixing the 2‑second DNS lookup lag on a Pi is a matter of:
- Disabling IPv6 when it’s not needed.
- Tuning the cache size to fit the device’s memory.
- Optionally enabling DoT for privacy.
- Using
resolvectlto inspect and adjust per‑link settings. - Monitoring statistics to confirm the fix.
The steps above are straightforward and can be scripted for multiple devices. Once in place, your Pi will resolve domains in a few milliseconds, keeping your homelab snappy and reliable.
See also
- Diagnosing a 30‑second Nginx start‑up lag on an 8‑core ARM home‑server
- When `ip link` shows no IP but you can ping: diagnosing an absent IPv4 on a bridge interface
- When Wayland Won’t Run My Games: Tweaking a Laptop for Better Battery Life
- When a backup script keeps my CPU pegged: a quick ps, nice, ionice tweak to keep the terminal responsive.
- Why my headphone jack stopped working after the latest update—and how a single udev rule brought it back