Zum Inhalt springen
labkompass

Guides · Netzwerk

Pi-hole mit Unbound: Werbefilter plus eigener rekursiver DNS

Warum Pi-hole allein deine DNS-Anfragen nur weiterreicht — und wie du mit Unbound als rekursivem Resolver unabhängig von Google, Cloudflare & Co. wirst. Mit kompletter Konfiguration.

Von Niclas Hennrich · Veröffentlicht: · aktualisiert · 9 Min. Lesezeit


Kurz gesagt: Pi-hole filtert Werbung, reicht die Namensauflösung aber nur an Google, Cloudflare oder deinen Provider weiter. Mit Unbound als rekursivem Resolver auf demselben Gerät (Port 5335, in Pi-hole als Upstream 127.0.0.1#5335) löst dein Netz selbst auf — mit DNSSEC-Validierung und ohne DNS-Historie bei Dritten.

Pi-hole blockt Werbung und Tracker im ganzen Netz — aber die eigentliche Namensauflösung reicht es nur weiter: an Google (8.8.8.8), Cloudflare (1.1.1.1) oder deinen Provider. Wer Selfhosting ernst meint, holt sich auch diesen Schritt ins Haus: Unbound als rekursiver Resolver fragt die DNS-Root-Server direkt — kein Dritter sieht mehr deine gesammelte DNS-Historie.

Wie die Kette danach aussieht #

Nach dem Umbau fragt dein Netz keinen fremden DNS-Anbieter mehr, sondern löst jede Domain selbst auf — von der Root-Zone abwärts. Der Unterschied zum Status quo: Ein Forwarder (das ist Pi-hole allein) reicht deine Frage komplett an einen fremden Server weiter und vertraut dessen Antwort. Ein rekursiver Resolver klappert die DNS-Hierarchie selbst ab.

Was bei einer Anfrage nach www.labkompass.de konkret passiert, wenn nichts im Cache liegt:

  1. Unbound fragt einen der 13 Root-Server: „Wer ist für .de zuständig?“ — und bekommt als Antwort einen Verweis auf die .de-Nameserver.
  2. Unbound fragt die .de-Server: „Wer ist für labkompass.de zuständig?“ — Verweis auf die autoritativen Nameserver der Domain.
  3. Unbound fragt den autoritativen Server nach dem A-Record von www.labkompass.de — und bekommt die IP-Adresse.
  4. Die Antwort geht zurück an Pi-hole, das sie an den Client durchreicht.

Klingt nach viel Hin und Her — passiert aber nur beim ersten Mal. Die Verweise auf .de und die autoritativen Server bleiben im Cache, jede weitere Anfrage in dieselbe Richtung spart sich die oberen Etagen.

Der Privacy-Gewinn steckt in der Verteilung: Beim Forwarding sieht ein Anbieter deine komplette DNS-Historie. Bei der Rekursion sieht jeder Beteiligte nur seinen Ausschnitt — der Root-Server nur „irgendwas unter .de“, der .de-Server nur die Domain, erst der autoritative Server die volle Anfrage (QNAME Minimisation, bei Unbound Standard). Kein einzelner Punkt hat das Gesamtbild.

Client → Pi-hole (filtert Werbung/Tracker)
            → Unbound (löst rekursiv auf, validiert DNSSEC)
                → Root- / TLD- / autoritative Server

Bonus nebenbei: Unbound validiert DNSSEC und cached aggressiv — nach kurzer „Aufwärmphase“ sind häufige Domains oft schneller beantwortet als über einen externen Forwarder.

Schritt 1: Unbound installieren #

Unbound ist ein einzelnes apt-Paket, installiert in einer Minute — auf demselben Gerät wie Pi-hole (Raspberry Pi, LXC, VM — egal):

sudo apt install unbound

Auf Debian und Raspberry Pi OS bringt die Installation über das Paket dns-root-data automatisch aktuelle Root-Hints und den DNSSEC-Trust-Anchor mit — das manuelle Herunterladen einer root.hints-Datei aus älteren Anleitungen ist hier unnötig. Ob der Dienst läuft, zeigt sudo systemctl status unbound.

Schritt 2: Unbound-Konfiguration für Pi-hole #

Eine einzige Konfigurationsdatei reicht: Unbound lauscht darin nur lokal auf Port 5335 und bekommt ein paar sinnvolle Härtungen. Die Datei anlegen als /etc/unbound/unbound.conf.d/pi-hole.conf:

server:
    verbosity: 0
    interface: 127.0.0.1
    port: 5335
    do-ip4: yes
    do-udp: yes
    do-tcp: yes
 
    # IPv6 aktivieren, wenn dein Anschluss es sauber kann
    do-ip6: no
    prefer-ip6: no
 
    harden-glue: yes
    harden-dnssec-stripped: yes
    use-caps-for-id: no
    edns-buffer-size: 1232
 
    prefetch: yes
    num-threads: 1
    so-rcvbuf: 1m
 
    # Private Adressbereiche nie aus öffentlichen Antworten akzeptieren
    private-address: 192.168.0.0/16
    private-address: 169.254.0.0/16
    private-address: 172.16.0.0/12
    private-address: 10.0.0.0/8
    private-address: fd00::/8
    private-address: fe80::/10

Die wichtigsten Zeilen kurz erklärt: interface: 127.0.0.1 bindet Unbound ausschließlich an localhost — nur Pi-hole auf demselben Gerät erreicht ihn. edns-buffer-size: 1232 vermeidet Probleme mit fragmentierten UDP-Paketen, prefetch erneuert beliebte Cache-Einträge kurz vor Ablauf, sodass sie praktisch nie „kalt“ werden. Die private-address-Blöcke sind Rebind-Schutz: Öffentliche DNS-Antworten, die auf private IPs zeigen, werden verworfen. Ob die Syntax stimmt, prüft unbound-checkconf; dann neu starten und testen:

sudo unbound-checkconf
sudo service unbound restart
dig labkompass.de @127.0.0.1 -p 5335

Die Antwort sollte status: NOERROR zeigen. DNSSEC-Gegenprobe: dig dnssec-failed.org @127.0.0.1 -p 5335 muss mit SERVFAIL abgelehnt werden — genau das ist das gewünschte Verhalten.

Schritt 3: Pi-hole auf Unbound umstellen #

Die Umstellung ist ein einziger Eintrag in der Weboberfläche — in der Pi-hole-Oberfläche unter Settings → DNS:

  1. Alle vorausgewählten Upstream-Server (Google, Cloudflare …) abwählen
  2. Bei Custom DNS eintragen: 127.0.0.1#5335
  3. Speichern

Ab jetzt läuft jede nicht gecachte Anfrage über deinen eigenen Resolver. Prüfen kannst du das im Query Log: Als Upstream steht nun 127.0.0.1#5335.

Eine Kleinigkeit noch: Die Option Use DNSSEC in Pi-hole bleibt aus. Unbound validiert bereits selbst — eine doppelte Validierung bringt nichts und produziert im Query Log irreführende „Bogus“-Einträge.

Schritt 4: Der Rest des Netzes #

Damit der Filter überhaupt greift, muss der DHCP-Server deines Routers die Pi-hole-IP als DNS an alle Geräte verteilen — je nach Setup:

FritzBox — Weg 1 (empfohlen): Unter Heimnetz → Netzwerk → Netzwerkeinstellungen → IPv4-Einstellungen das Feld Lokaler DNS-Server auf die Pi-hole-IP setzen. Die FritzBox verteilt diese Adresse dann per DHCP an alle Geräte — jede Anfrage geht direkt an den Pi-hole, und im Query Log taucht jedes Gerät einzeln auf. Wenn dein Anschluss IPv6 nutzt, gilt dasselbe unter IPv6-Einstellungen für den lokalen DNSv6-Server — sonst umgehen Geräte den Filter schlicht über IPv6.

FritzBox — Weg 2 (Ergänzung): Unter Internet → Zugangsdaten → DNS-Server die Pi-hole-IP als DNSv4-Server eintragen. Dann nutzt die FritzBox selbst den Pi-hole als Upstream — sinnvoll, damit auch die Anfragen der Box und des Gastnetzes durch den Filter laufen. Als einziger Weg taugt das aber nicht: Alle Clients erscheinen im Pi-hole dann nur noch als „fritz.box“, die Statistiken pro Gerät sind dahin.

DNS-Rebind-Schutz: Die FritzBox verwirft DNS-Antworten, die auf private IP-Adressen zeigen — ein sinnvoller Schutz, der zum Problem wird, sobald du eigene Hostnamen lokal auflöst (etwa nas.deinedomain.de auf 192.168.x.x): Solche Antworten unterdrückt die Box kommentarlos. Die Ausnahme trägst du unter Heimnetz → Netzwerk → Netzwerkeinstellungen → DNS-Rebind-Schutz ein, die betroffene Domain genügt. Unbound bringt über die private-address-Zeilen denselben Schutz mit — dort ergänzt du für solche Fälle private-domain: "deinedomain.de".

OPNsense: Im DHCP der jeweiligen Netze den Pi-hole als DNS ausliefern — oder Unbound gleich direkt auf der OPNsense betreiben; dann übernimmt die Firewall beide Rollen.

Absicherung: Warum kein offener Resolver #

Unbound gehört ausschließlich auf 127.0.0.1 — ein aus dem Internet erreichbarer Resolver wird binnen Stunden gefunden und für DDoS-Verstärkungsangriffe missbraucht. Die Konfiguration oben erledigt das bereits über interface: 127.0.0.1; kontrollieren kannst du es so:

sudo ss -tulpn | grep 5335

In der Ausgabe darf Unbound nur an 127.0.0.1:5335 gebunden sein, nicht an 0.0.0.0. Dieselbe Regel gilt eine Etage höher: Pi-hole lauscht zwar auf der LAN-IP (das muss es), aber Port 53 hat in einer Portfreigabe am Router nichts verloren. Den eigenen Filter unterwegs nutzen? Per VPN — WireGuard oder Tailscale sind der saubere Weg.

Docker oder bare metal? #

Beides funktioniert — auf einem dedizierten Raspberry Pi ist bare metal die robustere Wahl: zwei apt-Pakete, zwei systemd-Dienste, keine beweglichen Teile dazwischen. Für den einen Dienst, der wirklich immer laufen muss, ist das ein Feature. In Docker läuft das Gespann als zwei Container in einem gemeinsamen Netz; als Upstream trägst du dann statt 127.0.0.1#5335 den Containernamen ein (etwa unbound#53), denn localhost meint im Pi-hole-Container nur den Container selbst. Sinnvoll ist das vor allem, wenn auf dem Host ohnehin alles in Docker läuft — rechne aber mit den üblichen Stolperfallen um Port 53 (systemd-resolved). Und falls du noch schwankst, welcher Filter es sein soll: Pi-hole vs. AdGuard Home vergleicht beide.

Test und Diagnose #

Zwei dig-Befehle zeigen dir in einer Minute, ob die Kette steht. Erst Unbound direkt:

dig labkompass.de @127.0.0.1 -p 5335

Interessant sind drei Stellen der Ausgabe: status: NOERROR heißt, die Auflösung hat funktioniert; im ANSWER SECTION steht die IP; und die Query time ist bei der ersten Anfrage spürbar höher (volle Rekursion), bei der sofortigen Wiederholung fällt sie auf nahezu null — dann antwortet der Cache. Für DNSSEC die Probe in beide Richtungen:

dig +dnssec denic.de @127.0.0.1 -p 5335
dig dnssec-failed.org @127.0.0.1 -p 5335

Die erste Antwort muss im Header das ad-Flag tragen (authenticated data — Signaturkette geprüft). Die zweite muss mit SERVFAIL scheitern: dnssec-failed.org ist absichtlich kaputt signiert; käme hier NOERROR, würde Unbound nicht validieren.

Zum Schluss die ganze Kette von einem Client aus, mit der Pi-hole-IP:

dig labkompass.de @192.168.178.2

Läuft auch das durch und zeigt das Pi-hole Query Log als Upstream 127.0.0.1#5335, bist du fertig. Wenn nicht: journalctl -u unbound zeigt, was der Resolver zu meckern hat.

Wartung: Was regelmäßig anfällt #

Erfreulich wenig — nach der Einrichtung pflegt sich das Setup weitgehend selbst. Was tatsächlich anfällt:

  • Blocklisten (Gravity): Pi-hole aktualisiert seine Blocklisten einmal pro Woche automatisch per Cron. Manuell anstoßen, etwa nach dem Hinzufügen neuer Listen: pihole -g.
  • Pi-hole selbst: Updates kommen per pihole -up (bare metal) bzw. über ein neues Image (Docker). Ein Blick alle paar Wochen genügt.
  • Unbound: läuft über die normalen Systemupdates mit — sudo apt update && sudo apt upgrade. Den DNSSEC-Trust-Anchor hält das Paket selbst aktuell, da ist nichts zu tun.

Mehr ist es nicht. Ein gelegentlicher Blick ins Dashboard verrät trotzdem manches — etwa wenn die Anfragen plötzlich einbrechen, weil der Router sich wieder selbst als DNS verteilt.

Wenn der Pi-hole ausfällt #

Fällt dein einziger Pi-hole aus, funktioniert im ganzen Netz keine Namensauflösung mehr — „das Internet ist kaputt“, obwohl die Leitung steht. Dafür gibt es zwei ehrliche Antworten:

  • Zweiter Pi-hole: der übliche Weg — etwa als LXC auf dem Proxmox-Host, als zweiter DNS-Server im DHCP verteilt. Wichtig zu wissen: Clients nutzen zwei DNS-Server nicht brav nacheinander, sondern wechseln munter zwischen beiden. Der zweite Pi-hole braucht also dieselben Blocklisten und Einstellungen (Teleporter- Export oder ein Sync-Tool), sonst siehst du sporadisch doch Werbung.
  • Öffentlicher Fallback-DNS im DHCP (etwa 9.9.9.9 als zweiter Eintrag): hält das Netz am Laufen, ist aber aus demselben Grund kein echter „Fallback“ — ein Teil deiner Anfragen läuft dann im Normalbetrieb ungefiltert und wieder über einen Dritten. Damit gibst du einen Teil dessen auf, wofür du das alles gebaut hast.

Pragmatisch: Für ein Ein-Personen-Netz reicht oft ein einzelner Pi-hole plus das Wissen, wie man am Router notfalls in zwei Minuten den DNS zurückstellt. Sobald Mitbewohner oder Familie dranhängen, ist der zweite Pi-hole die entspanntere Lösung.

Häufige Fragen und Stolperfallen #

  • „Ist rekursives DNS langsamer?“ Die allererste Anfrage an eine Domain: ja, minimal (mehrere Nachfragen statt einer). Danach übernimmt der Cache. Im Alltag nicht spürbar.
  • Port 5335 statt 53: Absicht — auf 53 lauscht ja bereits Pi-hole. Unbound ist bewusst nur lokal (127.0.0.1) erreichbar.
  • unbound-control meldet Fehler / Logs voller Timeouts: Häufig blockt die Firewall ausgehende DNS-Anfragen (TCP/UDP 53) des Servers — Unbound muss selbst hinaus dürfen.
  • unbound-resolvconf.service funkt dazwischen: Auf manchen Systemen (Stichwort openresolv) trägt dieser Dienst Unbound ungefragt in die Auflösung des Hosts ein. Abhilfe: sudo systemctl disable --now unbound-resolvconf.service.
  • Router verteilt sich weiterhin selbst als DNS: Dann tauchen Geräte im Pi-hole nur als „Router“ auf. Für saubere Statistiken muss der DHCP die Pi-hole-IP direkt ausliefern.
  • Zweiter Pi-hole: DNS ist kritische Infrastruktur — fällt der einzige Pi-hole aus, „ist das Internet kaputt“ (für die Familie jedenfalls). Ein zweiter Pi-hole (z. B. als LXC auf dem Proxmox-Host) als sekundärer DNS ist der übliche Weg.

Fazit #

Pi-hole + Unbound ist eines der dankbarsten Selfhosting-Projekte überhaupt: eine halbe Stunde Aufwand, danach filtert und löst dein Netz vollständig selbst auf — schneller Cache, DNSSEC-Validierung und keine DNS-Historie mehr bei Dritten.

Häufige Fragen

Warum sollte ich Pi-hole mit Unbound kombinieren?
Pi-hole allein filtert zwar Werbung und Tracker, reicht die eigentliche Namensauflösung aber nur weiter — an Google, Cloudflare oder deinen Provider. Unbound als rekursiver Resolver fragt die DNS-Root-Server direkt: Kein Dritter sieht mehr deine gesammelte DNS-Historie, dazu kommen DNSSEC-Validierung und ein aggressiver Cache.
Ist rekursives DNS mit Unbound langsamer?
Nur die allererste Anfrage an eine Domain ist minimal langsamer, weil mehrere Nachfragen statt einer nötig sind. Danach übernimmt der Cache — im Alltag ist das nicht spürbar. Nach kurzer Aufwärmphase sind häufige Domains oft sogar schneller beantwortet als über einen externen Forwarder.
Warum läuft Unbound auf Port 5335 statt 53?
Absicht: Auf Port 53 lauscht ja bereits Pi-hole. Unbound ist zudem bewusst nur lokal auf 127.0.0.1 erreichbar.
Wie stelle ich Pi-hole auf Unbound um?
In der Pi-hole-Oberfläche unter Settings → DNS alle vorausgewählten Upstream-Server abwählen, bei Custom DNS 127.0.0.1#5335 eintragen und speichern. Ab dann läuft jede nicht gecachte Anfrage über den eigenen Resolver — im Query Log steht als Upstream nun 127.0.0.1#5335.
Wie teste ich, ob Unbound korrekt funktioniert?
Mit dig labkompass.de @127.0.0.1 -p 5335 — die Antwort sollte status NOERROR zeigen. Die DNSSEC-Gegenprobe dig dnssec-failed.org @127.0.0.1 -p 5335 muss dagegen mit SERVFAIL abgelehnt werden; genau das ist das gewünschte Verhalten.
Was passiert, wenn der Pi-hole ausfällt?
Dann funktioniert im ganzen Netz keine Namensauflösung mehr — DNS ist ein Single Point of Failure. Der übliche Weg ist ein zweiter Pi-hole als zweiter DNS-Server im DHCP, mit denselben Blocklisten. Ein öffentlicher Fallback-DNS im DHCP hält das Netz zwar am Laufen, ist aber kein echter Fallback: Clients nutzen beide Server parallel, ein Teil der Anfragen läuft dann ungefiltert an Dritte.
Kann ich Pi-hole und Unbound auch in Docker betreiben?
Ja — beide Container in einem gemeinsamen Docker-Netz, Unbound wird dann über den Containernamen als Upstream eingetragen. Auf einem dedizierten Raspberry Pi ist bare metal aber die einfachere und robustere Wahl: weniger bewegliche Teile für den einen Dienst, der immer laufen muss.

Weiterlesen