top of page
Search

The Problem Wasn’t NTP. It Was DNS. Obviously!

  • Writer: Shannon
    Shannon
  • Jan 2
  • 4 min read

More tales from the homelab!


I noticed another error in Pi-hole after upgrading to v6, but ultimately zero issues throughout the house. I don't trust these things and actually learned something I probably should've learned earlier. Figured I'd blog about it!


First off...the error:

Cannot resolve NTP server address: No valid NTP replies received, check server and network connectivity

That is one of those messages that immediately sends your brain in the wrong direction. You start thinking about UDP 123, firewall rules, maybe a flaky pool.ntp.org endpoint. All reasonable guesses. All wrong.


Because time was not actually the problem. DNS was.


It is always DNS.


I am running Pi-hole on Debian 12 in my home lab. Nothing unusual here. Pi-hole handles DNS for the network, blocks ads, forwards internal names to internal DNS, and sends everything else out to the internet. I also have an internal DNS zone, shakeen.net, backed by internal name servers for domain controllers and lab systems. This is a pretty common setup for anyone running a real lab instead of just a smart TV and a printer.

The mistake I made was subtle and very easy to justify at the time. I let the Pi-hole host itself use internal DNS.


When I finally stopped guessing and actually looked at /etc/resolv.conf, this is what I saw originally:

# Generated by NetworkManager
search shakeen.net
nameserver 192.168.1.194
nameserver 192.168.1.196

Those IPs are internal DNS servers.


At first glance, that feels reasonable. The Pi-hole host lives on the same network. Why would it not use the same DNS as everything else?


Here is where the chain reaction starts.


NTP needs DNS to resolve time servers like pool.ntp.org. Modern DNS, especially when DNSSEC is involved, needs accurate system time to validate responses. Pi-hole depends on DNS working correctly. And suddenly you have a circular dependency where DNS needs time, time needs DNS, and Pi-hole is sitting right in the middle of that loop.

Nothing is technically offline. Everything is just waiting on everything else.


Once I saw that, the fix stopped being mysterious.


The first thing I did was break the loop by giving the operating system a boring, reliable way to resolve names that had nothing to do with Pi-hole or internal DNS. On Debian 12 with NetworkManager, that meant explicitly setting external resolvers for the host itself. After updating the NetworkManager connection, /etc/resolv.conf looked like this:

# Generated by NetworkManager
search shakeen.net
nameserver 1.1.1.1
nameserver 8.8.8.8

This is intentional.


The Pi-hole host now always has working DNS, even if Pi-hole is stopped, restarting, or misconfigured. Almost immediately after this change, NTP recovered. A quick check with:

timedatectl

showed the system clock synchronized again, and the NTP errors disappeared from the logs. Time was flowing forward, which is generally something you want.


With the host stabilized, I could finally configure Pi-hole the way it is meant to be configured. Instead of mixing internal and external DNS servers as upstreams, I leaned on conditional forwarding so Pi-hole could make intelligent decisions about where queries should go.


In the Pi-hole admin UI, under Settings → DNS → Conditional Forwarding, I added two entries like this:

true,192.168.1.0/24,192.168.1.194,shakeen.net
true,192.168.1.0/24,192.168.1.196,shakeen.net

This tells Pi-hole that any client on my local network asking for something in shakeen.net should be forwarded to my internal DNS servers. Everything else continues upstream to external resolvers.


At the same time, I made sure the upstream DNS configuration in Pi-hole was clean. Either Pi-hole talks to Unbound on 127.0.0.1#5335, or it talks directly to public resolvers. What it does not do anymore is list internal DNS servers as general upstreams. Internal resolution is handled explicitly and only when appropriate.

Testing this is another place where it is easy to confuse yourself if you are not careful. Because the Pi-hole host itself is now using public DNS by design, running this will always fail:

dig shandc01.shakeen.net

That query goes straight to Cloudflare, which quite rightly responds with NXDOMAIN. That does not mean internal DNS is broken.


The correct test is to query Pi-hole directly:

dig shandc01.shakeen.net @127.0.0.1

When I did that, the record resolved immediately. Looking at the Pi-hole query log confirmed the behavior I wanted to see. Internal names were forwarded to 192.168.1.194 or 192.168.1.196, and external names were resolved normally.


One detail that looks suspicious but is actually fine is the search shakeen.net line in resolv.conf. That line only affects how short hostnames are expanded. If I type ping shandc01, the resolver will try shandc01.shakeen.net. Public DNS will return NXDOMAIN quickly, and the world keeps spinning. It does not override name servers, and it does not reintroduce the DNS loop.


Once everything was in place, the architecture finally matched the intent. Score one for learning something interesting over holiday break!


The Pi-hole host OS uses public DNS so it can always resolve time servers, package repositories, and certificate endpoints. Pi-hole handles DNS for clients and uses conditional forwarding for internal zones. Internal DNS remains authoritative for shakeen.net. Clients only ever talk to Pi-hole.


No circular dependencies. No broken clocks. No mysterious errors that only show up after a reboot.


The biggest takeaway here is that when a system tells you it cannot tell time, the problem is almost never time itself. It is trust. Who does this system trust for DNS, and what does that DNS depend on? If the answer involves the system trusting itself, you have found your issue. Whoops.


DNS is subtle. Time is unforgiving. And when you wire them together in the wrong order, the universe has a way of reminding you.


And yes, it was DNS the whole time.

Comments


© 2020 Shannon B. Eldridge-Kuehn

  • LinkedIn
  • Twitter
bottom of page