My Pi-hole died. Not gradually — every adlist failed to update, and once the cache expired, DNS for the entire network went with it. The obvious suspect was my ISP blocking outbound port 53, which is common enough that I spent a day building around it.
It was not the ISP. It was my own router — a UniFi Dream Router 7 — silently hijacking every DNS query on the network. Here is how to tell the difference, and how to fix it either way.
Symptoms
- Every adlist stuck in a failed state, serving from cache.
pihole -greturns Connection Refused on all lists.- Eventually, external resolution stops completely:
dig @127.0.0.1 example.comreturns no servers could be reached. - HTTPS browsing still works, so the network feels fine right up until it doesn’t.
That last point is what makes this confusing. Port 443 is untouched, so everything looks normal while your DNS infrastructure is quietly dead.
Step one: prove it is not Pi-hole
Test outbound port 53 from a machine that is not your Pi-hole, so you are testing the network rather than the service:
dig @8.8.8.8 example.com
dig @9.9.9.9 example.com
dig +tcp @8.8.8.8 example.comIf all of those time out while HTTPS works, outbound 53 is being interfered with somewhere between you and the internet. Pi-hole is a victim, not the cause.
Test more than one resolver. In my case 1.1.1.1 was unreachable on every port, including 443, which sent me down a wrong path early. Cloudflare’s resolver is a common target for filtering rules, so a single failing test proves less than you think.
Step two: it is probably your router, not your ISP
This is the part I got wrong. I attributed the block to my ISP because it already filters outbound ICMP, so it fit a pattern I had seen before.
The real cause was the Content Filtering feature on my own UniFi Dream Router 7. When you enable it on a network, it does not just block domains — it intercepts all outbound DNS on port 53 and redirects it to the gateway itself, so its own filtering can be applied. Any device pointed at an external resolver stops getting answers from that resolver, whether it knows it or not.
On the UDR7 this lives under Settings → Security → Content Filtering, and it is applied per network, not globally. That detail matters: I had it switched on for two of my networks and had long forgotten about it, so nothing in the router’s dashboard was flagging a problem. The filtering was working exactly as designed — it just also broke every resolver on those networks.
Before you rebuild your DNS stack around an ISP restriction that may not exist, check your own equipment for:
- Content filtering or “safe browsing” profiles applied per-network.
- Any “DNS redirect”, “force safe DNS” or DNS interception setting.
- Parental controls, which frequently implement themselves the same way.
The tell: a query to an external resolver returns an answer, but not the answer that resolver would give. If queries time out entirely, something is dropping rather than rewriting them.
The fix: DNS over HTTPS, upstream of Pi-hole
Whether the interception is your ISP or your own gateway, the durable fix is the same: stop using port 53 for outbound queries. Run a DoH client locally and point Pi-hole at it. Queries leave over 443, indistinguishable from normal web traffic, and you get upstream privacy as a side effect.
Do not reach for cloudflared. Cloudflare removed the proxy-dns feature in version 2026.2.0. Plenty of guides still recommend it and they no longer work. Use dnscrypt-proxy.
The chicken and egg problem
You need to download a DNS client, but you have no working DNS to resolve where to download it from. Break the loop by resolving over DoH and pinning the address in the same command:
curl --doh-url https://cloudflare-dns.com/dns-query \
--resolve cloudflare-dns.com:443:104.16.248.249 \
-LO https://github.com/DNSCrypt/dnscrypt-proxy/releases/latest/download/dnscrypt-proxy-linux_x86_64.tar.gz--resolve supplies the IP so no lookup is needed, and --doh-url handles any further resolution over HTTPS. This one command is the thing to remember from this article.
Configuration that actually matters
Two settings caused me real trouble. In dnscrypt-proxy.toml:
listen_addresses = ['127.0.0.1:5053']
# Pin static DoH servers by IP. Do not rely on a hostname you
# cannot resolve yet, and avoid resolvers your gateway blocks.
block_ipv6 = trueSet block_ipv6 = true if your network has no working IPv6. Otherwise the resolver returns AAAA records, Pi-hole’s FTL tries to reach them over a route that does not exist, and you get Connection Refused errors that look exactly like the problem you just fixed.
Then point Pi-hole at it — in /etc/pihole/pihole.toml:
upstreams = ["127.0.0.1#5053"]Back up that file first, restart FTL, and make sure the DoH service is enabled so it survives a reboot. A DNS resolver that does not come back after a power cut is a trap you set for your future self.
The second trap: the container resolves for itself
After all this, clients resolved perfectly — and pihole -g still failed. Pi-hole serves the network from its listener, but gravity and curl running inside the container use /etc/resolv.conf like any other program. Mine still pointed at 8.8.8.8 on port 53. Blocked.
Worse, editing /etc/resolv.conf did not stick. If you run Pi-hole in an LXC container, the hypervisor rewrites that file from the container’s configuration on every boot. Fix it at that level instead:
# Proxmox, replacing 103 with your container ID
pct set 103 --nameserver 127.0.0.1The diagnostic that pinned this down: HTTPS to a fixed IP succeeded every time, while the same request using normal name resolution failed. When connectivity works but resolution does not, stop looking at the network.
Verify
# External resolution through the new path
dig @127.0.0.1 example.com
# Local records still work
dig @127.0.0.1 myserver.lan
# Lists actually download now
pihole -g
# Both services survive a reboot
systemctl is-enabled dnscrypt-proxy pihole-FTLAll ten of my adlists updated cleanly, with no Connection Refused anywhere.
What I would tell myself a day earlier
Suspect your own equipment before your ISP. Consumer and prosumer routers increasingly intercept DNS by default, marketed as security or parental controls. On the UDR7 it is Content Filtering; other vendors ship the same behaviour under different names. It is not a fault, it is a feature you may not remember enabling — and it produces exactly the symptoms of an upstream block.
Test from a second machine. Everything I checked initially ran on the Pi-hole itself, which kept the investigation pointed at Pi-hole.
A service that resolves for others may not resolve for itself. Serving DNS to the network and using DNS internally are two different paths, and they can fail independently.
Moving to DoH was the right call regardless of the cause. Once your resolver stops depending on a port that anything between you and the internet feels entitled to rewrite, this entire class of problem disappears.