The thing nobody tells you when you set up a Pi-hole or AdGuard for the first time is how much of the internet is just tracking. Run it for 24 hours, look at the logs. The number of DNS queries from your "smart" TV to telemetry endpoints is genuinely insulting.
Why DNS-level beats per-device blocking
uBlock on a browser is great. It does nothing for the smart fridge that talks to four ad networks before breakfast. DNS-level blocking happens before any device makes a connection — at the resolver step. Block graph.facebook.com at the DNS layer and every app on every device on the network silently fails to phone home.
The other win: you don't have to install anything on the device itself. Phones, TVs, console, IoT — all of them just resolve through the same upstream and get the same blocklist applied. No per-device extension, no jailbreak required.
The setup
AdGuard Home runs in a Docker container on a Pi 4. Port 53 (DNS) bound to all interfaces; port 3000 (admin UI) bound to localhost only and exposed via SSH tunnel when I need it. The router's DHCP server hands out the Pi as the primary DNS for every connecting device.
# docker-compose.yml
services:
adguard:
image: adguard/adguardhome:latest
container_name: adguard
ports:
- "53:53/tcp"
- "53:53/udp"
- "127.0.0.1:3000:3000/tcp"
volumes:
- ./conf:/opt/adguardhome/conf
- ./data:/opt/adguardhome/work
restart: unless-stopped
Blocklists I actually use
| OISD Big | ~1.4M domains · ad + tracker base layer |
| HaGeZi Pro++ | aggressive · catches mobile telemetry |
| 1Hosts (Pro) | cross-list dedup · maintained well |
| NoCoin | cryptojacking domains |
| StevenBlack Hosts | fakenews + gambling extensions |
| Custom local | my own additions, e.g. specific TV brand telemetry |
Combined deduplicated list ends up around 2 million domains. AdGuard handles this in a hash table; resolution latency is microseconds compared to the network round-trip to the upstream resolver. You will not feel it.
DoH upstream
Blocking ads at the DNS layer is half the win. The other half is making sure my ISP doesn't see the unblocked queries. AdGuard upstream is set to https://cloudflare-dns.com/dns-query over DNS-over-HTTPS. The ISP sees encrypted traffic to Cloudflare; nothing in the clear.
The query log is also a free intrusion detector. If a device on your LAN suddenly starts making DNS requests to n7d8s9.ddns-something-suspicious.tk at 3am, you have an answer to a question you didn't know to ask. I've caught one IoT device this way that turned out to be in a botnet.
What breaks
Be honest about this. AdGuard breaks things sometimes. App stores occasionally use the same CDN as ad networks. Some banking apps refuse to work without telemetry. The right answer is per-client overrides — my phone has a relaxed list, the TV has the strictest. AdGuard supports that natively via client identification by IP.
Once you watch your own DNS logs for a week, you stop being able to use the internet without DNS filtering. The amount of background telemetry on a "normal" home network is staggering.
Stack with PiVPN
I run AdGuard alongside PiVPN on the same Pi. When I'm off-network on my phone, I tunnel home and still resolve through AdGuard — so the blocklist follows me. It's a small thing that took ten minutes to set up and I'd miss it daily if it broke.