Your smart TV makes more phone calls than you do, and none of them are to you. A DNS blocker screens those calls for the whole house, from one small box instead of one app per device.
The short answer
Pi-hole and AdGuard Home do the same core job. They answer your devices' DNS questions and send a dead-end answer for names on a blocklist [8][11]. Both are free, and both run on a small Linux machine or in Docker. Our assessment: take Pi-hole if you like organising lists and devices in groups, take AdGuard Home if you want encrypted DNS in and out, plus parental-control features, without extra software. Neither one can block an ad that is served from the same domain as the content, such as ads inside YouTube videos [13].
How it works
- What a DNS blocker does. Before a device connects to a name like
ads.example, it asks a resolver for the address (our article on DNS name resolution explains the chain). A blocker is a resolver with a blocklist. For a listed name it answers with nothing useful instead of the real address. Pi-hole's default is the "unspecified address",0.0.0.0and::, so clients should not even try to connect [8]. Because this happens per name, it covers every app and every device that uses the blocker, smart TVs and consoles included, without installing anything on them [11]. - What it cannot do. AdGuard's FAQ is blunt: any ad that shares a domain with the content cannot be blocked at DNS level unless you block the content too. It names YouTube and Twitch ads and sponsored posts on Facebook, X and Instagram, and says DNS alone will never be enough for this [13]. A banner inside a page is invisible to DNS as well, because DNS only ever sees names. Treat a DNS blocker as a coarse first filter. A browser extension still catches things it cannot.
- The two tools in October 2026. Pi-hole v6 has an embedded web server and API inside the
pihole-FTLbinary, solighttpdand PHP are gone, plus native HTTPS and a singlepihole.tomlfile [5]. The newest Docker release, 2026.10.0 of 17 Oct 2026, bundles Core 6.5, FTL 6.8 and Web 6.6.1 [6]. The docs ask for 512 MB RAM and 2 GB free disk (4 GB recommended), list Alpine, Armbian, Debian, CentOS Stream, Fedora, Raspberry Pi OS and Ubuntu as supported systems, and want a static address, where a DHCP reservation is enough [1]. AdGuard Home's stable release is v0.107.79 from 18 Aug 2026. A beta channel (v1.0.0-b.1, 30 Sep 2026) has switched to a new interface and version scheme, so we stay on stable here [17]. Its binaries cover Linux, macOS, Windows and BSD [17]. Be careful with the vendors' own comparison tables. AdGuard's README, as retrieved on 24 Oct 2026, still says that Pi-hole needs manuallighttpdwork for HTTPS [11], which predates Pi-hole v6's built-in HTTPS [5]. - Lists and rules. Pi-hole subscribes to blocklists and, since v6, to allowlists as well (called Antigravity) [5]. Domains, regex filters and lists can be sorted into groups [9]. AdGuard Home reads three syntaxes: Adblock-style, hosts-file style and plain domain lists. In Adblock-style,
||example.org^blocks a domain and its subdomains,@@||example.org^lets it through again, and/REGEX/matches by regular expression. Adblock-style lists also work in browser blockers [15]. AdGuard also checks answers for CNAME cloaking, where an innocent-looking name secretly points to a blocked tracker [13]. Whatever you use, subscribe to a few lists, not forty. Every extra list adds names that may break something you need (our assessment). - Rules per device. Pi-hole does this through groups that you assign to clients [9]. AdGuard Home has per-client configuration [11]. Both can only tell devices apart if the queries arrive from the devices themselves. Behind a router that forwards everything, all queries may look like one client (our assessment, so check the query log).
- Encrypted DNS. Plain DNS travels in the clear (see our DNS article). AdGuard Home supports encrypted upstreams and can serve DNS-over-HTTPS and DNS-over-TLS to your clients [11]. For Pi-hole, AdGuard's table says this needs additional software [11]. A pull request merged on 17 Jul 2026 adds native DoT and DoH upstreams to Pi-hole's FTL [10]. The FTL v6.8 release notes of 17 Oct 2026 do not list it [18], so we treat it as not yet in a stable release. Read the release notes before you rely on it.
- Install and ports. Pi-hole's one-step installer is
curl -sSL https://install.pi-hole.net | bash. The docs also show how to read the script first, or use Docker [2]. Pi-hole answers on port 53 (TCP and UDP), serves its interface on 80 and 443, and uses 67 for the optional DHCP server [1]. AdGuard Home needs 3000/TCP for the first-run wizard, 80/TCP for the interface and 53 for DNS [12]. A service installs withsudo ./AdGuardHome -s install[12]. If something else already holds port 53, nothing starts. Ubuntu'ssystemd-resolvedis the usual culprit, and AdGuard's FAQ lists the fix [13]. - Pointing devices at it. Three ways, best first. Hand out the blocker's address as DNS server in your router's DHCP settings. Or use the blocker's own DHCP server after switching DHCP off on the router. Or set it device by device as a last resort [3]. AdGuard describes the router route as well [12]. Our assessment: a second DNS server that does not filter will be used by some clients, which defeats the filter. If you add a backup, make it a second filter.
- Keep it inside the house. Pi-hole's firewall examples only admit your local ranges, because it was designed to work inside a local network [1]. AdGuard's hardening page tells you to bind the DNS server to a loopback or LAN interface, and to use access settings and rate limiting (default 20) if a server must be reachable from outside [16]. Updates matter. The Pi-hole 2026.10.0 release lists fixes for 17 security advisories across FTL, Web and Core [6]. AdGuard Home v0.107.79 fixed a resource-exhaustion issue in DNS-over-QUIC [17]. Pin a version, and move to the next tag on purpose after you have read its notes.
- What speaks against both. A blocker is a single point of failure. If it stops, every lookup fails and the network looks offline. Pi-hole's own docs warn about this for the host that uses itself as resolver [3]. False positives happen, and the one that breaks a login or a shop checkout is the one your family notices (our assessment). Devices with a hardcoded resolver, or a browser with its own encrypted DNS, skip your blocker entirely. The query log is a diary of your household, so decide how long it should keep entries. Many small sites live on ads, so allowlist the ones you want to support. If all you want is a quiet browser, an extension is less work than a server.
Side by side
| Pi-hole | AdGuard Home | |
|---|---|---|
| Version checked, 24 Oct 2026 | Docker 2026.10.0: Core 6.5, FTL 6.8, Web 6.6.1 [6] | stable v0.107.79, beta v1.0.0-b.1 [17] |
| Runs on | listed Linux systems or Docker [1] | Linux, macOS, Windows, BSD or Docker [17] |
| Licence | EUPL 1.2, as named in its contribution template [10] | GPL-3.0 [11] |
| Rule syntax | lists, regex, groups [9] | Adblock-style, hosts, domains, regex [15] |
| Per-device rules | groups [9] | per-client settings [11] |
| Encrypted upstream | extra software; native support merged, not in a stable release [10][11][18] | built in [11] |
| Serves DoH or DoT | extra software [11] | built in [11] |
| Parental control, safe search | via extra blocklists [11] | built in [11] |
| Optional DHCP server | yes [1] | yes [11] |
A homelab example
Bytearium has no DNS ad blocker on record. As of 14 to 18 Oct 2026 our inventory lists an internal DNS server as planned, not running, and we say nothing about a filter. What follows is a general walkthrough for your own Linux box, not a report from ours. Both tools are shown with a pinned image tag that exists on Docker Hub as of 24 Oct 2026 [7][14]. Pick one, because they would fight over port 53.
Pi-hole, tag 2026.10.0. The compose file follows the Pi-hole docs [4], with the web ports moved to 8080 and 8443. Put the password into a .env file as PIHOLE_PASSWORD=..., not into the compose file:
services:
pihole:
container_name: pihole
image: pihole/pihole:2026.10.0
ports:
- "53:53/tcp"
- "53:53/udp"
- "8080:80/tcp"
- "8443:443/tcp"
environment:
TZ: "Europe/Berlin"
FTLCONF_webserver_api_password: "${PIHOLE_PASSWORD}"
FTLCONF_dns_listeningMode: "ALL"
volumes:
- "./etc-pihole:/etc/pihole"
restart: unless-stoppedThe docs say listeningMode: ALL is needed on Docker's default bridge network [4]. It also means the container accepts queries on every interface it sees, so never publish port 53 to the internet. Start it with docker compose up -d.
AdGuard Home, tag v0.107.79. The volumes and ports follow the project's Docker instructions [12][14]. Port 3000 is only for the first-run wizard:
services:
adguardhome:
container_name: adguardhome
image: adguard/adguardhome:v0.107.79
ports:
- "53:53/tcp"
- "53:53/udp"
- "3000:3000/tcp"
- "8081:80/tcp"
volumes:
- "./work:/opt/adguardhome/work"
- "./conf:/opt/adguardhome/conf"
restart: unless-stoppedOpen http://<server-ip>:3000, click through the wizard, and remove the 3000 line afterwards. AdGuard's docs do not auto-update Docker installs, so you change the tag yourself [12].
If Docker reports address already in use for port 53 on Ubuntu, systemd-resolved is holding it. The fix from AdGuard's FAQ is a file /etc/systemd/resolved.conf.d/adguardhome.conf with these lines [13]:
[Resolve]
DNS=127.0.0.1
DNSStubListener=noThen point /etc/resolv.conf at the file systemd-resolved keeps without the stub, and restart the service. Skip this step and the host itself can no longer resolve names [13]:
sudo mv /etc/resolv.conf /etc/resolv.conf.backup
sudo ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf
sudo systemctl reload-or-restart systemd-resolvedTest before you touch the router. On a laptop, run nslookup example.org <server-ip>, which should answer normally. Then look up a name from your blocklist; with Pi-hole's default mode the answer is 0.0.0.0 [8]. Last, change one device's DNS server, run nslookup example.org and check that the "Server" line shows the blocker, and that the request appears in the query log [13]. Only then change the router's DHCP DNS setting.
Checklist
- Check what you want to block. If the answer is "ads in YouTube", a DNS blocker is the wrong tool.
- Decide between the two with the table: groups and a lean footprint, or encrypted DNS and parental control built in.
- Give the server a fixed address or a DHCP reservation before you point anything at it.
- Pin the image tag, write down the date, and read the release notes before you change it.
- Test with
nslookupagainst the server's address before you change the router. - Keep port 53 and the admin interface off the internet.
- Subscribe to a few lists and check the query log first when something stops working.
- Plan for the blocker being down: know how to switch the router's DNS back in one step.
- Check the query-log retention and delete entries you do not need.