Wie viele Geräte bei dir zu Hause haben einen Werbeblocker? Der Laptop, im Browser. Vielleicht das Handy, auch im Browser. Der Fernseher hat keinen, die Spielkonsole nicht, die Wetter-App nicht, der Staubsaugerroboter nicht, und das Smart-TV-Betriebssystem telefoniert fröhlich nach Hause, ohne dass irgendein Plugin dazwischenfunkt. Ein Blocker pro Gerät ist ein Wettlauf, den man nicht gewinnt. Ein Blocker für das ganze Netz ist ein Nachmittag Arbeit, einmal. AdGuard Home ist so ein Blocker: ein DNS-Server, der jede Adressanfrage im Haus sieht und Werbe- und Tracking-Domains einfach nicht beantwortet. Auf sakis.tech lief dafür bisher Pi-hole; AdGuard Home ist die andere große Option, und für ein paar Leute die bessere. Welche das sind, steht unten. Erst mal läuft es.

Was AdGuard Home macht, und warum es alle Geräte erwischt
Jedes Gerät, das eine Webseite öffnet oder eine App startet, stellt vorher eine Frage: Welche IP-Adresse hat dieser Name? Das ist DNS, und die Antwort kommt normalerweise vom Router, der sie beim Provider holt. AdGuard Home setzt sich an diese Stelle. Fragt der Fernseher nach dem Werbenetzwerk, antwortet AdGuard Home mit einer Null-Adresse, und die Werbung lädt ins Leere. Fragt er nach der Mediathek, reicht AdGuard Home die Frage an einen echten DNS-Server weiter und merkt sich die Antwort. Das Gerät selbst merkt davon nichts, deshalb funktioniert es auch auf Geräten, auf denen man nichts installieren kann.
Wer hier schon mit Pi-hole und Unbound unterwegs ist, kennt das Prinzip. AdGuard Home macht dasselbe mit anderen Schwerpunkten: Verschlüsseltes DNS zum Upstream (DNS-over-HTTPS, DNS-over-TLS) ist eingebaut, ohne zweiten Container. Die Blocklisten wählt man per Klick aus einer gepflegten Auswahl, darunter die HaGeZi-Listen, die du vielleicht aus dem Fritz-Hole-Beitrag kennst. Und die Oberfläche zeigt pro Gerät, was es fragt, mit eigenen Regeln pro Gerät, wenn man will. Das Projekt gibt es seit 2016, es steht unter GPL-3.0, hat rund 37.400 Sterne auf GitHub und wurde zuletzt gestern angefasst. Die stabile Version ist v0.107.79 vom 18-08-2026; seit dem 30-09-2026 gibt es eine Beta von 1.0 mit neuer Oberfläche. Die nehmen wir nicht. Ein DNS-Server, der ausfällt, nimmt das ganze Heimnetz mit, und das ist kein Dienst, an dem ich Betas teste.
Was du brauchst
- Einen Linux-Server mit Docker und Docker Compose. Prüfen mit
docker compose version. Fehlt Docker, hilft die Docker-Compose-Anleitung für Einsteiger. Das Image gibt es für amd64 und arm64, ein Raspberry Pi ist also dabei. - Einen freien Port 53, den DNS-Port. Prüfen mit
sudo ss -ulnp | grep ':53 ' || echo "Port frei". Auf Ubuntu ist er fast immer belegt, und zwar vonsystemd-resolved; das räumt Schritt 2 auf. Läuft dort schon Pi-hole, musst du dich entscheiden, zwei Filter auf einem Port gehen nicht. - Einen freien Port 3000 für die Oberfläche. Prüfen mit
ss -tlnp | grep 3000 || echo "Port frei". Wie du einen Belegten findest, steht in Port belegt? So findest du den Schuldigen. - Eine feste IP-Adresse für den Server. Prüfen mit
hostname -I; die erste Adresse ist die richtige. Fest heißt: Der Router vergibt sie immer wieder an dieses Gerät. Ein DNS-Server, der morgen eine andere Adresse hat, ist ein Heimnetz ohne Internet. - Zugang zu deinem Router, weil er am Ende allen Geräten sagt, wo der neue DNS wohnt.
- IP-Adresse deines Servers:
192.168.178.53 - Dein Router:
192.168.178.1 - Ordner für die Compose-Datei:
~/adguard - Port der Oberfläche:
3000, Port für DNS:53 - Name des Admin-Benutzers:
sakis
Schritt 1: Ordner und Compose-Datei anlegen
Zuerst ein Ordner, in dem alles liegt, was AdGuard Home gehört. Der Befehl legt ihn an und wechselt hinein.
mkdir -p ~/adguard && cd ~/adguardDann die Compose-Datei. Der Editor nano öffnet eine leere Datei; Inhalt einfügen, mit Strg+O und Enter speichern, mit Strg+X schließen.
nano docker-compose.ymlIn den leeren Editor kommt dieser Inhalt:
services:
adguardhome:
image: adguard/adguardhome:v0.107.79
container_name: adguardhome
restart: unless-stopped
network_mode: host
volumes:
- ./work:/opt/adguardhome/work
- ./conf:/opt/adguardhome/confNeun Zeilen, und drei davon sind eine Entscheidung:
imagemit Versionsnummer. Das Taglatestzeigt heute auf dieselbe Version, aber nach einem Update zeigt es auf irgendetwas, und bei einem DNS-Server will ich wissen, was ich starte. Die Version änderst du selbst, wenn du updatest (unten mehr).network_mode: host. Der Container benutzt das Netz des Servers direkt, ohne die übliche Docker-Zwischenschicht. Ohne diese Zeile sieht AdGuard Home jede Anfrage so, als käme sie vom Docker-Netz selbst: Laptop, Fernseher und Handy wären im Dashboard ein einziges Gerät mit einer Adresse wie 172.17.0.1. Das offizielle Docker-Wiki sagt es genau so, und in Diskussion #2736 auf GitHub steht die Geschichte von jemandem, der sich gewundert hat, warum nur ein Client auftaucht. Der Preis: Die Zeileports:entfällt, und was AdGuard Home belegt, belegt es direkt auf dem Server, deshalb die Port-Prüfung oben.- Zwei Ordner,
workfür Daten (Protokoll, Statistik, Listen) undconffür die eine Konfigurationsdatei. Beide liegen neben der Compose-Datei, undconf/AdGuardHome.yamlist später dein Backup.
Ob die Datei sauber ist, sagt Docker, bevor irgendetwas startet:
docker compose config --quiet && echo "Datei ok"Datei okKommt stattdessen eine Fehlermeldung mit Zeilennummer, ist es fast immer die Einrückung: YAML zählt Leerzeichen, und ein Tabulator ist keins.
Jetzt das Image laden, und zwar bevor Schritt 2 an den DNS des Servers geht. Der Grund steht dort; die Kurzfassung: Wer Port 53 freiräumt, nimmt dem Server für ein paar Minuten die Namensauflösung, und ohne Namensauflösung findet Docker den Docker Hub nicht. Das Image liegt danach lokal, und der Start in Schritt 3 braucht kein Netz mehr. Die zweite Zeile zeigt zum Beweis, was angekommen ist.
docker compose pull --quiet && docker image ls adguard/adguardhome --format '{{.Repository}}:{{.Tag}}'adguard/adguardhome:v0.107.79Schritt 2: Port 53 freiräumen
Auf Ubuntu und vielen anderen Systemen läuft systemd-resolved, ein kleiner DNS-Vermittler, der auf 127.0.0.53:53 lauscht. AdGuard Home will auf allen Adressen Port 53, und das geht nicht, solange dort jemand sitzt. Erst nachsehen:
sudo ss -ulnp | grep ':53 ' || echo "Port frei"Steht da Port frei, überspringst du den Rest von Schritt 2. Steht da eine Zeile mit systemd-resolve, nimmst du den Weg aus der offiziellen FAQ: Eine kleine Konfigurationsdatei schaltet den Lauscher ab und sagt dem System, dass es ab jetzt bei 127.0.0.1 fragt, also bei AdGuard Home. Der Block prüft in der ersten Zeile selbst, ob systemd-resolved überhaupt läuft; wenn nicht, tut er nichts.
if systemctl is-active --quiet systemd-resolved; then
sudo mkdir -p /etc/systemd/resolved.conf.d
printf '[Resolve]\nDNS=127.0.0.1\nDNSStubListener=no\n' | sudo tee /etc/systemd/resolved.conf.d/adguardhome.conf
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-resolved
fiWas hier passiert, Zeile für Zeile: Der Ordner für Zusatz-Konfigurationen wird angelegt, die Datei mit zwei Einstellungen hineingeschrieben (DNSStubListener=no ist die, die den Port freigibt), die bisherige /etc/resolv.conf wird als Backup beiseitegelegt und durch die Fassung ersetzt, die systemd-resolved selbst pflegt, und zuletzt liest der Dienst seine Konfiguration neu. Dieselbe Prüfung wie oben muss jetzt anders ausgehen:
sudo ss -ulnp | grep ':53 ' || echo "Port frei"Port freiEin Hinweis, bevor du weitergehst: Dein Server fragt ab jetzt bei sich selbst nach Namen, bei 127.0.0.1, und sonst bei niemandem. Solange AdGuard Home noch nicht läuft, antwortet dort keiner, und der Server kann für den Moment keinen einzigen Namen auflösen: kein apt update, kein docker pull, kein curl auf eine Domain. Genau deshalb liegt das Image seit Schritt 1 schon auf der Platte. Was jetzt noch kommt, braucht kein Netz, und zwei Minuten später läuft AdGuard Home und der Server ist sein eigener erster Kunde. Wer Schritt 1 zu Ende gelesen hat, merkt davon nichts; wer den Pull übersprungen hat, landet unten bei „Wo es klemmt".
Schritt 3: Starten und anklopfen
cd ~/adguard
docker compose up -d[+] up 1/1
✔ Container adguardhome Started 0.5sDas Image liegt seit Schritt 1 schon da, deshalb ist das in einer Sekunde erledigt und kommt ohne Netz aus. Dann zwei Kontrollen: Läuft der Container, und antwortet die Oberfläche?
docker compose ps --format '{{.Name}} {{.State}}'
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/adguardhome running
302Die 302 ist eine Weiterleitung: AdGuard Home schickt jeden, der auf Port 3000 anklopft, zur Einrichtungsseite, weil es noch keine Konfiguration hat. Beim Nachbau stand die Antwort sechs Sekunden nach dem Start da. Das ist die Sorte „läuft sofort", bei der ich zweimal hinsehe, aber das Image ist eine einzige Go-Datei ohne Datenbank, da gibt es wenig, was warten müsste.
Schritt 4: Der Assistent auf Port 3000
Jetzt in den Browser. Der Assistent hat fünf Seiten, und auf einer davon triffst du eine Entscheidung, die später zählt.
Im Browser http://192.168.178.53:3000 öffnen (Stand AdGuard Home v0.107.79). Die Seite Welcome to AdGuard Home! erscheint; unten Get Started klicken.
Schritt 2 von 5, „Admin Web Interface": Listen interface auf All interfaces lassen und bei Port die vorgeschlagene 80 durch 3000 ersetzen. Darunter DNS server: All interfaces, Port 53, beides so lassen. Dann Next.
Schritt 3 von 5, „Authentication": bei Username sakis eintragen, bei Password und Confirm password ein langes Passwort. Next.
Schritt 4 von 5, „Configure your devices": nur lesen, das machen wir in Schritt 6 anders. Next.
Schritt 5 von 5, „Congratulations!": Open Dashboard klicken, mit sakis und dem Passwort anmelden (Sign in). Du siehst das Dashboard mit DNS Queries und Blocked by filters, beide noch bei null.
Die Entscheidung ist der Admin-Port. AdGuard Home schlägt 80 vor, und 80 ist auf einem Homelab-Server oft schon vergeben, an einen Reverse Proxy zum Beispiel. Mit 3000 bleibt die Oberfläche unter der Adresse erreichbar, die du gerade im Browser hast, und nichts kollidiert. Zeigt die Seite bei Port 53 einen roten Hinweis mit einem Knopf Fix: nicht drücken. Der Knopf will systemd-resolved abschalten, aber er läuft im Container, und von dort aus ist dein Server für ihn unerreichbar. Der Weg ist Schritt 2.
Ob der DNS-Teil wirklich antwortet, beweist eine Anfrage direkt am Server. Die erste Zeile fragt eine normale Seite ab, die zweite eine Domain, die in der vorinstallierten Liste „AdGuard DNS filter" steht:
nslookup sakis.tech 127.0.0.1
nslookup adserver.yahoo.com 127.0.0.1Server: 127.0.0.1
Address: 127.0.0.1#53
Non-authoritative answer:
Name: sakis.techName: adserver.yahoo.com
Address: 0.0.0.0Die erste Antwort nennt darunter die echte Adresse von sakis.tech. Die zweite ist der Moment, für den man das alles macht: 0.0.0.0 heißt, AdGuard Home hat die Frage gesehen und absichtlich ins Leere beantwortet. Das ist der Standard-Blockmodus laut Konfigurations-Doku: Null-Adresse für alles, was eine Adblock-Regel trifft. Im Dashboard steht jetzt bei Blocked by filters eine 1.
Schritt 5: Eine bessere Blockliste
Ab Werk ist genau eine Liste aktiv, der „AdGuard DNS filter". Die ist solide und klein. Wer mehr Werbung weghaben will, nimmt eine HaGeZi-Liste dazu; die Auswahl ist eingebaut, du musst keine URL suchen. HaGeZi gibt es in vier Stufen, Normal, Pro, Pro++ und Ultimate, und ich nehme Pro: deutlich mehr Einträge als Normal, und noch nicht die Größe, bei der jede zweite Login-Seite eine Ausnahme braucht. Je länger die Liste, desto öfter steht man im Query Log und gibt etwas frei.
Oben im Menü Filters, dann DNS blocklists (Stand AdGuard Home v0.107.79). Rechts Add blocklist klicken, im Dialog Choose blocklists. In der Gruppe General den Haken bei HaGeZi's Pro Blocklist setzen, unten Save.
Die Tabelle zeigt jetzt zwei Zeilen: AdGuard DNS filter und HaGeZi's Pro Blocklist, beide mit Schalter auf An und einer Regelzahl in der Spalte dahinter.
Die Listen aktualisiert AdGuard Home von selbst, alle 24 Stunden. Wenn eine Seite plötzlich nicht mehr geht, ist Query Log im Menü die erste Adresse: Dort steht die blockierte Domain, und daneben ein Knopf, der sie freigibt.
Schritt 6: Ein Gerät umstellen, dann der Router
Bis hierher filtert AdGuard Home nur für den Server selbst. Jetzt kommt der Rest des Hauses, und ich würde das in zwei Stufen tun: erst ein Gerät von Hand, dann der Router für alle. Wenn beim einzelnen Gerät etwas hakt, hat niemand sonst ein Problem. Am Laptop trägst du 192.168.178.53 als DNS-Server ein; unter Windows ist das Systemsteuerung → Netzwerk und Internet → Netzwerk- und Freigabecenter → Adaptereinstellungen ändern, Rechtsklick auf die aktive Verbindung, Eigenschaften, Internetprotokoll, Version 4 (TCP/IPv4), Eigenschaften, dann Folgende DNS-Serveradressen verwenden. Am Handy steht dasselbe in den WLAN-Einstellungen des verbundenen Netzes. Dann am Laptop in einem Terminal:
nslookup adserver.yahoo.comName: adserver.yahoo.com
Address: 0.0.0.0Oben steht als Server 192.168.178.53, und im Dashboard taucht unter Top clients die Adresse des Laptops auf, als eigenes Gerät, mit eigener Zeile. Das ist die Zeile, die es ohne network_mode: host nicht gäbe.
Dann der Router. Bei einer FritzBox sind es zwei Stellen, und ich habe sie im FritzBox-Beitrag zu Pi-hole Schritt für Schritt beschrieben, samt IPv6 und Gastnetz; die Adresse ist dieselbe, nur dass jetzt AdGuard Home dahinter sitzt. Die Kurzfassung für die Stelle, die alle Geräte erwischt:
In der FritzBox unter Heimnetz → Netzwerk → Netzwerkeinstellungen den Abschnitt IPv4-Einstellungen öffnen und bei Lokaler DNS-Server die 192.168.178.53 eintragen, Übernehmen. Die Geräte bekommen den neuen DNS, sobald sie ihre Adresse erneuern, spätestens nach einem WLAN-Neustart.
Den Eintrag am Laptop aus dem ersten Teil kannst du danach wieder auf „automatisch" stellen. Nach einer Stunde zeigt Top clients das Haus: jedes Gerät mit Adresse, der Fernseher meist ganz oben. Kurz freuen ist hier erlaubt.
Was am Ende eingestellt ist
- Ein Admin-Benutzer, Oberfläche unverschlüsselt. Die Anmeldung schützt die Einstellungen, aber Port 3000 spricht HTTP im ganzen Heimnetz. Im eigenen WLAN ist das vertretbar; von außen erreichbar machst du diesen Port nie, auch nicht „nur kurz". Von unterwegs geht es per VPN, etwa mit wg-easy, und dann filtert AdGuard Home auch dein Handy im Mobilfunknetz.
- Upstream prüfen. Wen AdGuard Home fragt, wenn es eine Antwort nicht kennt, steht unter Settings → DNS settings bei Upstream DNS servers. In Issue #5744 nennt ein Nutzer als Werkseinstellung Quad9 über DNS-over-HTTPS; sieh selbst nach, was bei dir steht, und trag ein, wem du vertraust. Mit Test upstreams prüft die Seite den Eintrag, mit Apply gilt er. Wer gar niemanden fragen will, hängt einen eigenen Unbound davor, wie im Pi-hole-und-Unbound-Beitrag; die Adresse des Unbound-Containers kommt dann hier hinein.
- Protokoll und Statistik. Das Anfrage-Protokoll behält AdGuard Home 90 Tage, die Statistik 24 Stunden, beides nach den Vorgaben im Quellcode. 90 Tage jede DNS-Anfrage jedes Familienmitglieds ist viel; unter Settings → General settings stellst du Query logs rotation auf eine Woche und Statistics retention auf eine Woche, dann hast du genug zum Nachsehen und wenig zum Verlieren.
- Updates machst du selbst. Der Knopf Update now, den AdGuard Home sonst zeigt, ist im Docker-Image abgeschaltet; die Startzeile des Images enthält
--no-check-update, und die Doku sagt für Docker: Image tauschen. Also in der Compose-Datei die Versionsnummer ändern, danndocker compose pull && docker compose up -d. Die Ordnerworkundconfbleiben dabei unangetastet. Die Release-Notes vorher lesen, vor allem, sobald die 1.0 stabil wird. - Backup ist eine Datei. Alles, was du eingestellt hast, steht in
~/adguard/conf/AdGuardHome.yaml: Benutzer, Listen, Upstreams, Regeln. Die Datei auf eine andere Platte kopieren, und das Backup ist erledigt; ja, schon wieder der Satz, er bleibt trotzdem wahr. Die Datei von Hand ändern willst du nur bei gestopptem Container, sonst überschreibt AdGuard Home deine Änderung, das steht so in der Konfigurations-Doku.
Wo es klemmt
- „address already in use" bei Port 53: der Dauergast, seit 2019 in Issue #1289 und seither in der FAQ. Fast immer
systemd-resolved, also Schritt 2. Auf Systemen ohnesystemd-resolvedist es ein anderer DNS-Dienst, zum Beispiel ein alter Pi-hole oderdnsmasq;sudo ss -ulnp | grep ':53 'nennt den Prozess. - „failed to resolve reference … lookup registry-1.docker.io … connection refused" beim Start: Docker will das Image laden und findet den Docker Hub nicht, weil Schritt 2 die Namensauflösung schon auf
127.0.0.1gestellt hat, wo noch niemand antwortet. Das passiert genau dann, wenn der Pull aus Schritt 1 übersprungen wurde. Der kürzeste Weg zurück: Schritt 2 für einen Moment rückgängig machen, also die Datei/etc/systemd/resolved.conf.d/adguardhome.conflöschen, den Link/etc/resolv.confentfernen und das Backup/etc/resolv.conf.backupwieder an seine Stelle schieben, dannsudo systemctl restart systemd-resolved. Jetzt hat der Server wieder DNS: den Pull-Block aus Schritt 1 ausführen, danach Schritt 2 noch einmal von vorn, und dann erst Schritt 3. - Alle Geräte heißen 172.17.0.1: Dann steht in deiner Compose-Datei
ports:stattnetwork_mode: host. Docker schiebt die Anfragen durch seinen Proxy, und AdGuard Home sieht nur dessen Adresse. Diskussion #2736 auf GitHub, und die Lösung ist die Zeile aus Schritt 1. - Oberfläche nach dem Assistenten weg: Wer in Schritt 4 den Port 80 stehen lässt, findet AdGuard Home danach unter
http://192.168.178.53ohne Portnummer, oder gar nicht, wenn dort schon ein anderer Dienst wohnt. Die Portnummer steht inconf/AdGuardHome.yamlunterhttp: address; Container stoppen, Zahl ändern, starten. - Der Fix-Knopf im Assistenten: gut gemeint, aber im Container ohne Wirkung auf den Server darunter. Wenn er erscheint, ist Port 53 noch belegt: zurück zu Schritt 2.
- Eine Seite lädt nicht mehr: Im Query Log nach der Domain suchen, dort steht, welche Liste sie blockt, und ein Klick setzt sie auf die Allowlist. Je größer die Liste, desto öfter kommt das vor; das ist der Preis, den Pro++ und Ultimate kosten.
Pi-hole oder AdGuard Home?
Beides filtert, beides läuft hier im Nachbau. Wenn du Pi-hole hast und zufrieden bist, gibt es keinen Grund zu wechseln. Wenn du neu anfängst, würde ich AdGuard Home nehmen, sobald eines von drei Dingen zutrifft: Du willst verschlüsseltes DNS zum Upstream ohne zweiten Container, du willst Regeln pro Gerät (das Kinder-Tablet strenger als der Arbeitslaptop), oder du willst Listen per Klick statt per URL. Pi-hole bleibt vorn bei der Community-Größe und bei dem, was in Foren schon einmal gelöst wurde. Das ist kein kleiner Punkt, wenn um 23 Uhr das Netz steht.
Welche Liste läuft bei dir, und was hat sie als Erstes zu Unrecht geblockt? Schreib's in die Kommentare, mich interessiert vor allem, ob HaGeZi Pro bei euch irgendwo im Weg war.
Wer AdGuard Home jetzt laufen hat und den Router nicht anfassen will oder darf: Der FritzBox-Beitrag beschreibt auch, was mit IPv6 und dem Gastnetz zu tun ist, damit die Werbung nicht durch die Hintertür zurückkommt.
Quellen
- AdGuard Home Knowledge Base: Docker (Ports, Volumes, --network host, Update)
- AdGuard Home Wiki: Docker (Client-IPs und host network)
- AdGuard Home Knowledge Base: Getting Started (erster Start auf Port 3000, Geräte und Router)
- AdGuard Home Wiki: Getting Started (Updates bei Docker abgeschaltet)
- AdGuard Home FAQ: Port 53 und systemd-resolved
- AdGuard Home Wiki: Configuration (blocking_mode, Datei nur bei gestopptem Dienst ändern)
- config.go: Vorgaben für Protokoll (90 Tage), Statistik (24 Stunden), Standard-Listen
- build.Dockerfile: CMD mit --no-check-update
- Beschriftungen der Oberfläche (en.json)
- Hostlists Registry: die eingebaute Listenauswahl
- AdGuard DNS filter (enthält ||adserver.yahoo.com^)
- Releases: v0.107.79 vom 18-08-2026, v1.0.0-b.1 vom 30-09-2026
- Docker Hub: adguard/adguardhome (Tags, Architekturen)
- Diskussion #2736: alle Clients mit derselben Adresse
- Issue #1289: Docker und systemd-resolved auf Port 53
- Issue #5744: Standard-Upstream nach der Installation