Choosing and Tuning DNS Blocklists Without Breaking Websites

Choosing and Tuning DNS Blocklists Without Breaking Websites

An electricity bill payment freezes at the step where the OTP should appear. No error, just a spinner and then a blank panel. The reasonable assumption is that the state utility site is having a bad evening, and it is the wrong one if somebody added two new blocklists to the house resolver that afternoon and mentioned it to nobody. The query log settles the question in about fifteen minutes: one of those lists carries a domain used by the payment gateway’s fraud-check script, and with that name refusing to resolve, the checkout flow simply stops. A single allowlist entry brings the OTP back. What to do about the list itself is the more interesting question, and the answer is to remove it, because a blocklist that costs you a payment at nine in the evening is not earning its place, however many entries it advertises.

what a blocked answer actually looks like

Terminal: dig against the filter at 192.168.1.10 returns a real address for an allowed name, 0.0.0.0 for one blocked name, and NXDOMAIN with zero answers for another.
NXDOMAIN makes clients give up cleanly; 0.0.0.0 can leave some apps waiting.

Before tuning anything, it helps to see what your filter is doing. A blocking resolver does not intercept the page; it answers a name lookup with something useless on purpose. There are two common shapes, and they behave differently in apps.

# A name that is not blocked
dig +short @192.168.1.10 technobabu.com

# A blocked name answered with an unroutable address
dig +short @192.168.1.10 tracker.example
0.0.0.0

# A blocked name answered as if it does not exist
dig @192.168.1.10 tracker.example | grep -E 'status|ANSWER:'
# status: NXDOMAIN, ANSWER: 0

NXDOMAIN means “no such name” and clients give up cleanly. Answering 0.0.0.0 makes the client try an address that goes nowhere, which usually fails fast but can leave some apps waiting. I choose NXDOMAIN where the filter allows it, because honest failure causes less odd behaviour than a hanging connection.

This is also the first check when someone says a site is broken. If dig returns 0.0.0.0 or NXDOMAIN for a domain that should exist, the filter is your suspect, and you have saved an hour of blaming the ISP.

the four kinds of list, and what each one costs

Table of four blocklist types: advertising with low risk, tracking with low to moderate risk, malicious domains with very low risk, and aggressive lists with high risk.
Malicious-domain lists are the least glamorous and the most useful.

Every list is a text file of domain names, but they are not interchangeable. Lumping them together is how people end up with a filter they do not trust.

List typeWhat it blocksBreakage riskMy view
AdvertisingAd-serving and exchange domainsLowStart here, it is the safest ground
Tracking and telemetryAnalytics, fingerprinting, device call-homeLow to moderateWorth running, expect a rare login quirk
Malicious domainsPhishing hosts, malware distribution, scam pagesVery lowThe one I would keep even if I ran no others
Aggressive or “annoyance” listsSocial widgets, comment systems, CDN edges, whole categoriesHighAdd one at a time or not at all

That third row is the one I wish more people led with. Malicious-domain lists are the least glamorous and the most useful, because a name that never resolves cannot deliver a fake “your phone is infected” page to your mother’s browser, on any device in the house.

The fourth row is where payment-page failures like the one above come from. Aggressive lists reflect broad judgement calls about what counts as annoying, and some of those calls will not match how your household uses the internet.

why stacking twenty lists makes things worse

Four problems with stacking many blocklists: duplicated entries, more false positives, harder debugging and higher memory use.
A dashboard percentage measures chatty devices, not filtering quality.

The instinct is understandable. If one list is good, twelve must be better, and the admin dashboard rewards you with a bigger number. What actually happens is less pleasant.

  • Massive duplication. Popular lists are themselves compiled from other lists. Ten sources can share the overwhelming majority of their entries, so your domain count grows while your coverage barely moves.
  • False positives multiply. Every list you add is another maintainer’s judgement you have silently accepted. Twenty lists means twenty chances that somebody blocked a domain your bank needs.
  • Debugging gets painful. When something breaks you now have to find which of twenty sources carries the entry, and whether removing it will be undone at the next update.
  • Memory and load grow. On a Pi with other services running, an enormous blocklist database is real memory you could have spent elsewhere.

A dashboard percentage is not a quality score either. It mostly measures how chatty your devices are. One smart TV retrying a blocked telemetry endpoint every few seconds will inflate that figure beautifully without your browsing being any cleaner.

the small stack worth running

Three-layer blocklist stack: the filter's default set, one unified advertising and tracking list, and one curated malicious-domain list.
Three sources. A fourth rarely adds coverage the first three lack.

Three sources, and a fourth rarely adds coverage the first three lack. A well-maintained unified advertising and tracking list as the base, one curated list aimed at malicious and phishing domains, and the filter’s own default set. When something breaks, the offender is one search away.

Choose sources that publish how they add and remove entries and that have a visible history of fixing mistakes. A list last updated three years ago is worse than no list: the internet moved on, and stale entries for domains that have since changed hands are exactly how you get inexplicable breakage.

test for breakage before your family finds it

Six checks after changing blocklists: a one-rupee UPI payment, net banking past the OTP, single sign-on, a food delivery payment screen, courier tracking and a news site.
Test the same evening, while you still remember what you changed.

After any list change, run the same short circuit. It takes about ten minutes and it catches the kind of fault that otherwise surfaces at the worst possible moment.

  1. A UPI payment of one rupee to your own account. It is the flow most likely to break and the one people notice hardest.
  2. Log in to net banking and reach the page after the OTP, not just the login screen.
  3. Sign in to something with a Google or Apple account, since single sign-on pulls in several third-party domains.
  4. Reach the payment screen in Swiggy or Zomato, then back out.
  5. Track a courier shipment. Those sites lean hard on third-party scripts.
  6. Open a news site your family reads and check it is readable, not a stack of empty boxes.

Do this on the same evening you change lists, while you still remember what you changed. A list added on Tuesday that breaks a form on Saturday is a hard problem; the same fault found ten minutes later is trivial.

the allowlisting workflow when something breaks

Flow: reproduce the failure with the log open, find the blocked domain, allowlist that single domain, and record why.
A filter you keep patching is a filter you will eventually switch off.
Terminal: pihole allow for a payment gateway domain, pihole -q to find which list carries a domain, and pihole -t for a live query tail.
pihole -q answers ‘which list did this’ in one line.

You need a routine here, because the instinct under pressure is to disable filtering entirely and never turn it back on. Work through it in order instead.

  1. Reproduce the failure with the page open and the query log open beside it. Filter the log by the device’s IP.
  2. Look at the blocked entries in the seconds around the failure. The culprit is usually something plausible next to the site’s own name.
  3. Allowlist the single most likely domain, not the whole pattern. Reload. If it works, stop.
  4. If not, add the next candidate and repeat. One at a time, so you learn which entry was actually responsible.
  5. Write it down. A comment on the allowlist entry naming the site that needed it, and the month, will save future you a lot of guessing.
# Pi-hole from the command line
pihole allow gateway-check.example.com
pihole -q doubleclick.net        # which of my lists carries this domain?
pihole -t                        # live tail of queries while you reload the page

If you find yourself allowlisting five domains for one site, the list is a poor fit for you. Remove the list. A filter you keep patching is a filter you will eventually switch off.

regex and wildcards, used sparingly

Comparison: anchored regex rules for a telemetry subdomain and metrics hosts are safe; an unanchored .*ads.* rule blocks loads and downloads too.
Test a pattern against a few real names before saving it.

Both Pi-hole and AdGuard Home accept pattern rules, which are powerful and also the easiest way to break your network in one line. A wildcard blocks a name and everything beneath it, which is fine for a telemetry subdomain and catastrophic if you aim it at a domain that also serves content you need.

# Wildcard: blocks telemetry.vendor.example and everything under it
(^|\.)telemetry\.vendor\.example$

# Anchored pattern for a family of metrics hosts
^metrics[0-9]*\.vendor\.example$

# The kind of rule that will hurt you: matches far more than you meant
.*ads.*

That last one looks clever and will block domains containing “loads”, “downloads” and “headspace-ads-free” along with everything you intended. Anchor your patterns, test them against a few real names before saving, and keep the total number of regex rules small enough that you can read them all in one screen.

Those are Pi-hole regex entries. AdGuard Home wraps regular expressions in slashes, for example /^metrics[0-9]*\.vendor\.example$/, and for a name plus everything beneath it the simpler rule ||telemetry.vendor.example^ does the same job.

keeping lists fresh without surprises

Lists change upstream, so what you block today is not what you approved last month. Pi-hole refreshes through pihole -g on a schedule, AdGuard Home has an update interval in settings. Both are fine defaults, and both mean a maintainer’s new entry can break your Saturday without you touching anything.

Two habits help. Note the date whenever you change your list set, so an unexplained failure can be checked against it. And keep your allowlist in a file outside the filter, because rebuilding a Pi and losing every hard-won allowlist entry along with it is a special kind of annoying. Which filter you run barely matters for this; I compared the two I trust in AdGuard Home versus Pi-hole, and the tuning discipline is identical either way.

One more piece of the picture. Lists only apply to queries that reach your filter, so a phone on mobile data is unfiltered the moment it leaves your Wi-Fi, which is the gap Android’s Private DNS setting exists to close. And if you want the answers behind your filter to be validated rather than taken on trust, that is the recursive resolver setup.

FAQ

a site says my ad blocker is on. what should i do?

Respect the request or leave. Those notices exist because advertising pays the writers. If it is a site you value, allowlist its domains and keep the rest of your network protected; if not, close the tab. Home filtering should be about refusing trackers and malicious hosts on your own network, not about taking content outside the arrangement the site asked for.

should i block a whole country or ip range through dns?

DNS filtering is not the right layer for that; it works on names, not addresses. People who try usually end up with a huge rule set and mysterious breakage. If you need address-level rules, that belongs in your firewall, and you should be honest about how much maintenance you are signing up for.

why did a site break only for one device?

Usually caching. Another device may hold a good answer from before the list change, while the affected one asked after it. Sometimes it is the opposite: one device is using its own encrypted DNS and never sees your filter at all, so it works when everything else fails. Check what resolver that device is actually using before you go hunting through lists, and my Pi-hole setup guide covers pinning devices to your own resolver at the router.

Tuning a blocklist is less about finding the perfect source and more about keeping the set small enough to reason about at nine in the evening. Start with advertising and malicious domains, test a payment, and add anything else one list at a time.

Update history: added AdGuard Home’s rule syntax next to the Pi-hole regex examples, updated the Pi-hole documentation link, and removed sections that repeated the guide.

Sources