Project Rebel Homebase: Teil 3

Die Hardware steht, jetzt bekommt die Rebellion ihr Gehirn. Warum „zwei Pi-holes im DHCP“ kein Cluster sind und wie wir mit Keepalived, Unbound und einer virtuellen IP echte digitale Souveränität bauen. Schluss mit Werbung, Tracking und Google DNS. Der „Stormtrooper“ erwacht.

Der 'Rebel Cube' Homelab-Server im schwarz-weißen Stormtrooper-Design. Ein ZimaBlade, zwei Raspberry Pi Blades als redundanter DNS-Cluster, ein 2.5G PoE-Switch und ein 10G-Switch als Basis.
Der Cube, liebevoll „The Stormtrooper“ genannt. Der Look des Imperiums aber das Herz der Rebellion. Und es ist ist sichergestellt, dass dieses System sein Ziel niemals verfehlt.

Der erste Meilenstein ist erledigt. Die Hardware aus Teil 1 (Die Idee) und Teil 2 (Die Hardware) steht. Die ersten beiden Blades sind montiert, das Netzwerk leuchtet. Alles bereit für Kubernetes und die großen Container-Schlachten, oder?

Falsch.

Wenn diese Homebase mehr sein soll als ein Spielplatz für ein paar Wochen, dann braucht sie verlässliche Basissysteme. Das Schwierigste erledigt? Träumt weiter. Was jetzt kam, hat mein Verständnis von Infrastruktur extrem vorangebracht.

Was euch heute erwartet

Ein Erlebnisbericht, eine Dokumentation und Anleitung.
Zielgruppe 1: Neugierige Nicht-Admins mit Leidensfähigkeit.
Zielgruppe 2: Erfahrene Admins zur Unterhaltung und zum Schmunzeln.

Dieser Text ist kein klassischer kurzer Blogartikel und kein kompaktes How-To. Er ist furchtbar lang. Und langweilig. Und das ist nötig. Er ist ein Protokoll gescheiterter Annahmen und (so hoffe ich) eine vollständige, reproduzierbare Dokumentation.

Er richtet sich an Menschen, die sich mit selbst betriebener souveräner Infrastruktur auseinandersetzen, sich durchbeißen, immer wieder scheitern und trotzdem weitermachen. Wenn du erwartest, dass Dinge „einfach funktionieren“: falscher Text. So war es nicht.

Einordnung: Ich bin kein Admin (und du vielleicht auch nicht)

Wenn du diesen Text liest, bist du wahrscheinlich kein gelernter Systemadministrator. Ich bin es auch nicht.

Ich kann mir Dinge erarbeiten. Ich kann Zusammenhänge verstehen. Aber ich scheitere regelmäßig an Stellen, an denen Dokumentationen einfach voraussetzen, dass man weiß, warum man gerade etwas tut. Dieser Artikel ist deshalb absichtlich langsam, pedantisch und vollständig. Nicht, weil DNS kompliziert sein muss, sondern weil es unforgiving ist. Es verzeiht keine Fehler. Und bitte ... testet immer. Ich habe jeden einzelnen Schritt recht mühselig lernen müssen.


Warum wir rebellieren

„Jede Rebellion beginnt mit Hoffnung.“

Das wissen wir von Cassian Andor.
Spätestens seit Rogue One.
Aber worauf hoffen wir hier, wenn wir Server in den Keller schrauben? Wir hoffen auf Autonomie. Und dasss Menschen dazulernen können.

Bevor wir tief in Config-Dateien abtauchen, müssen wir kurz klären, warum wir das hier tun. Warum nutzen wir nicht einfach Google DNS (8.8.8.8) oder Cloudflare (1.1.1.1)? Das wäre bequem. Es wäre kostenlos. Es wäre in 5 Sekunden eingerichtet.

Aber Bequemlichkeit ist der Käfig, den Big Tech erfolgreich um uns gebaut hat.

Jedes Mal, wenn wir die Infrastruktur der großen Hyperscaler nutzen, zahlen wir mit dem einzigen, was wir wirklich besitzen: unseren Daten und unserer Unabhängigkeit.

  • Closed Source ist eine Blackbox. Wir wissen nicht, was darin passiert.
  • Hyperscaler zentralisieren das Internet. Wenn us-east-1 hustet, bekommt das halbe Internet eine Lungenentzündung.
  • Digitale Souveränität bedeutet, dass ich entscheide, ob mein Fernseher nach Hause telefoniert, nicht der Hersteller (dazu kommen wir auch noch).

Wir bauen diese Homebase nicht, weil es einfacher ist. Wir bauen sie, weil es notwendig ist, um ein Stück Freiheit zurückzuerobern. Wer seine Basisinfrastruktur (DNS) aus der Hand gibt, hat den Kampf schon verloren, bevor er begonnen hat. Und Dezentralisierung ist der einzige Weg zu wirklicher Resilienz.

Das hier ist kein Hobby-Projekt. Es ist der Bau eines digitalen Schutzraums.


It’s always DNS... oder wie ich lernte, meinen Router nicht mehr anzubrüllen

Hand aufs Herz: Wie oft hieß es schon „Das Internet geht nicht!“, nur um festzustellen, dass eigentlich nur der DNS-Server klemmt? AWS, Microsoft und Cloudflare hatten Ende 2025 mehrere leidvolle Episoden dieser Art, ihr werdet euch erinnern.

DNS und Zeit (NTP) sind keine „Nice-to-Haves“. Sie sind:

  • Die Grundlage für alles, was später kommt (Matrix, OpenCloud/Nextcloud, Authentifizierung etc.).
  • Der Single Point of Failure in 99 % aller Heimnetze.
  • Und gleichzeitig eines der am meisten unterschätzten Probleme.

Wer hier pfuscht, baut ein Kartenhaus.


Meine Infrastruktur-Grundsätze (oder: Warum wir es kompliziert machen)

Warum installiere ich nicht einfach AdGuard Home auf dem Router und fertig? Warum nicht gleich alles in den Kubernetes-Cluster werfen?

Weil ich Infrastruktur-Grundsätze definiert habe, die über „es funktioniert gerade irgendwie“ hinausgehen.

1. Trennung der Gewalten (Die Hardware-Wahl)

Ich nutze für DNS und NTP zwei dedizierte Raspberry Pi CM4 Blades (Blade 01 & 02).

  • Warum CM4 mit 8 GB RAM? Ist das nicht Overkill für DNS? Ja. Aber DNS darf nie aus Speichermangel oom-killed (Out of Memory) werden. Es muss atmen können.
  • Warum nicht im Kubernetes-Cluster? Henne-Ei-Problem. Wenn der Cluster crasht (und das wird er am Anfang), brauche ich ein funktionierendes DNS, um ihn zu reparieren. Basisinfrastruktur muss unterhalb der Anwendungsebene liegen.

Mit Kanonen auf Spatzen schießen? Vielleicht. Aber dieser Spatz (Werbung & Tracker) ist danach definitiv tot. Oder anders gesagt: Overengineering ist nur ein anderes Wort für 'Ich will nachts ruhig schlafen'.

2. Zeit ist Wahrheit (Warum NTP wichtig ist)

Ein Raspberry Pi hat keine BIOS-Batterie (RTC) wie ein PC oder ein Handy. Nach einem Stromausfall denkt er, es ist 1970. Moderne Sicherheit (Kerberos, SSL-Zertifikate, 2FA) bricht sofort zusammen, wenn die Uhren nicht synchron sind. Logs werden nutzlos, wenn die Zeitstempel falsch sind. Deshalb werden diese beiden Nodes auch meine NTP-Server für das gesamte Netz.

3. Digitale Souveränität (Open Source only & No Cloud)

Keine Abhängigkeit von Google DNS, keine Abhängigkeit von Cloudflare für interne Auflösung. Wenn das Internetkabel durchgeschnitten wird, muss mein Haus intern weiter zu 100 % funktionieren.


Die Strategie der Namen: Domains & Identität

Ein Punkt, über den ich lange gegrübelt habe, ist das Naming.

Warum feste IPs und FQDNs?

In vielen Heimnetzen heißt der Server raspberrypi.local und hat irgendeine DHCP-Adresse. Das ist für ein Rebel Setup inakzeptabel.

  • Feste IPs sind wie Hausnummern im Grundbuch. Unveränderlich.
  • FQDN (Fully Qualified Domain Names): Wir nutzen dns1.pandolin.online statt nur dns1. Warum? Weil wir später vielleicht echte SSL-Zertifikate wollen. Und Zertifizierungsstellen validieren keine .local Domains.

Das Zwei-Welten-Prinzip (.io vs. .online)

Ich trenne meine digitale Identität strikt:

  1. pandolin.io: Das ist meine öffentliche Visitenkarte. Mein Blog, Cloud-Dienste, E-Mail. Das liegt im „bösen“ Internet.
  2. pandolin.online: Das ist meine Homebase. Meine Lab-Umgebung. Meine Daten. Betonung auf "mein".

Split-Horizon DNS (Der heilige Gral)

Der Clou an diesem Setup: Ich nutze intern wie extern für die Homebase dieselbe Domain (*.pandolin.online).

  • Bin ich unterwegs, löst home.pandolin.online auf meine öffentliche VPN-IP auf.
  • Bin ich zu Hause, löst home.pandolin.online direkt auf die interne LAN-IP (192.168.1.x) auf.

Das bedeutet: Meine Geräte müssen nie umkonfiguriert werden. Egal wo ich bin, die Dienste heißen gleich. Das nennt man „Split Horizon DNS“ – und genau das bauen wir heute.


Das Zielbild

Am Samstag habe ich beschlossen, dem Spuk ein Ende zu bereiten und den nächsten Schritt zu gehen. Mein Ziel: Eine hochverfügbare DNS-Infrastruktur mit Ad-Blocking und voller Datensouveränität. Wenn ein Server ausfällt, soll der andere nahtlos übernehmen – ohne dass Netflix auch nur ruckelt.

Die Zielsetzung war simpel formuliert – und komplex umzusetzen:

  • Linux only (Ubuntu 24.04 LTS)
  • Split-Horizon: Gleiche Namen intern wie extern
  • Transparenz: Ich will sehen, welches Gerät welche Tracker aufruft (Pi-hole)
  • Souveränität: Eigener rekursiver Resolver (Unbound) statt Google
  • Echte Redundanz: Nicht einfach zwei IP-Adressen im Router eintragen (das ist Glücksspiel), sondern eine virtuelle IP, die immer antwortet.

In diesem Abenteuer-Guide nehme ich dich/euch mit auf die Reise durch mein Setup mit Ubuntu 24.04 LTS, Pi-hole, Unbound und Keepalived. Wir bauen nicht nur, wir lernen auch, denn ich bin in ein paar fiese Fallstricke getreten. Damit du es hoffentlich nicht musst.


Warum DNS immer der erste echte Schmerz ist

Hand aufs Herz:
Wie oft hieß es schon „Das Internet geht nicht“, und am Ende war es nur DNS?

Ende 2024 / 2025 hatten AWS, Microsoft, Cloudflare und andere mehrere massive Ausfälle. Nicht wegen Hardware, sondern wegen DNS.

DNS ist:

  • unsichtbar
  • selbstverständlich
  • und wenn es kaputt ist, fühlt sich alles andere auch kaputt an
    Genau deshalb habe ich beschlossen, hier zuerst professionell zu werden.

Erste naive Annahme: Zwei Pi-holes reichen

Meine erste Idee war simpel:

Ich baue zwei Pi-holes. Trage beide im Router ein. Fertig ist die Redundanz.
Das ist falsch.

Warum?

Ein Client (Windows, macOS, Linux, Fernseher, Handy):

  • bekommt mehrere DNS-Server
  • entscheidet selbst, welchen er fragt
  • wechselt nicht zuverlässig, wenn einer nicht antwortet

Das Ergebnis geht es manchmal, manchmal hängt alles, niemand weiß warum.

Zwei DNS-Server im DHCP sind wie zwei Kassen im Supermarkt: Wenn an der ersten die Kassiererin einschläft, wartest du trotzdem erst mal stur fünf Minuten, bevor du die Schlange wechselst.

Definieren wir das Zielbild

Bevor wir irgendetwas installieren, muss klar sein, wie es sich anfühlen soll, wenn es fertig ist.

Ziel:

  • Alle Geräte im Haus kennen nur eine DNS-Adresse
  • Diese Adresse funktioniert immer
  • Wenn ein Server ausfällt, merkt es niemand

Diese eine Adresse nennt man VIP, die virtuelle IP.

Sie gehört nicht fest zu einem Server. Sie wird dynamisch übernommen. Von dem Server, der gerade gesund ist. Eine wandernde Hausnummer.

In diesem Setup ist die VIP die 192.168.1.5
Alle Clients und Services reden mit nur .5.
Welcher der existierenden DNS-Server antwortet, ist egal.


Schritt 1: Zwei Server, die sich selbst korrekt benennen können

Wir beginnen nicht mit DNS. Wir beginnen mit Namen.
Warum?

Weil Logs ohne Namen nutzlos sind, Reverse DNS später sonst Chaos produziert und man sonst nie weiß, welcher Server gerade antwortet.


Ausgangspunkt

  • 2× Raspberry Pi Blades mit CM4, 8 GB Ram, 256 Gb Nvme, 1 GBit Anbindung
  • Ubuntu 24.04 LTS Server
  • Netzwerk funktioniert grundsätzlich (Internet geht, IP-Adressen werden verteilt etc.)

Wir nennen sie:

dns1.pandolin.online

dns2.pandolin.online


Der erste echte Stolperstein: Ubuntu 24.04 & cloud-init

Fast jede Anleitung sagt dir: „Bearbeite /etc/hosts.“ Das funktioniert nicht dauerhaft unter Ubuntu 24.04.

Warum?

Ubuntu nutzt cloud-init, auch auf Bare Metal. Ein Self-Healing. Diese Komponente überschreibt /etc/hosts beim Booten.

Das merkst du so:

  • Du trägst etwas ein
  • Es funktioniert
  • Du rebootest
  • Alles ist weg und auf dem Ausgangszustand.
  • Grmpf.

Die korrekte Lösung (eine Stunde später)

Wir bearbeiten das Template, nicht die Datei selbst.

Auf dns1:

sudo hostnamectl set-hostname dns1.pandolin.online

Jetzt das Template öffnen:

sudo nano /etc/cloud/templates/hosts.debian.tmpl

Inhalt minimal und bewusst:

127.0.0.1 localhost 
127.0.1.1 dns1.pandolin.online dns1

Warum 127.0.1.1?
Weil Ubuntu diesen Eintrag intern erwartet, und alles andere später zu Warnungen führt.

Speichern, dann:

sudo reboot

Test: Hat es wirklich funktioniert?

Nach dem Neustart:

hostname 
hostname -f

Erwartung:

dns1.pandolin.online

Wenn hier noch irgendetwas anderes steht dann nicht weitermachen. Zurück. Das hier ist die Basis. Wenn es klappt, das selbe bitte mit korrespondierenden Werten auf dns2.


Schritt 2: Feste IP-Adressen – warum „automatisch“ hier dein Feind ist

Bis hierhin haben wir nur Namen gesetzt.
Jetzt kommt der nächste Punkt, an dem viele Anleitungen lakonisch sagen: „Vergib eine statische IP.“ Das klingt banal. Ist es nicht. Server ohne feste IP sind wie Hotelgäste. Bald wieder weg.

Warum feste IPs zwingend notwendig sind

Ein DNS-Server mit wechselnder IP ist wie ein Telefonbuch, das jede Nacht umzieht. Du kannst darauf aufbauen, aber du wirst es später bereuen.

Für unser Setup gilt deshalb:

  • dns1.pandolin.online192.168.1.3
  • dns2.pandolin.online192.168.1.4
  • die virtuelle IP (VIP) kommt später (192.168.1.5)

Diese 3 IPs dürfen sich niemals ändern.


Wie Ubuntu 24.04 Netzwerke konfiguriert (kurz, aber wichtig)

Ubuntu nutzt Netplan.
Das ist kein Dienst, sondern ein Konfigurationsformat, das beim Booten Netzwerkinterfaces, IP-Adressen, Gateways und DNS-Resolver setzt.

Das Entscheidende: Wenn Netplan falsch ist, hast du kein Netzwerk. Und damit auch oft auch keinen SSH-Zugriff mehr.

Deshalb hier langsam und bewusst voran.


Die Netplan-Datei erstellen

Auf dns1:

sudo nano /etc/netplan/01-static.yaml

Falls die Datei nicht existiert: kein Problem, neu anlegen.

Inhalt für dns1:

network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: no
      addresses:
        - 192.168.1.3/24
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses:
          - 9.9.9.9
          - 149.112.112.112

Was passiert hier im Detail?

  • dhcp4: no „Nein, ich möchte keine automatische IP.“
  • addresses Das ist unsere Identität im Netz.
  • via: 192.168.1.1 Das ist mein Router (DreamWall).
  • nameservers Das ist nur temporär. Später ersetzt Pi-hole das. Jetzt brauchen wir es, damit das System selbst DNS kann.

Der Moment der Wahrheit

sudo netplan apply

Wenn jetzt keine Fehlermeldung kommt und die SSH-Verbindung nicht abbricht passt alles.
Wenn die Verbindung abbricht, ruhig bleiben, Tippfehler suchen.


Tests - und bitte nicht überspringen:
ip a

Du willst dieses Ergebnis:

inet 192.168.1.3/24

Dann:

ping -c 3 192.168.1.1

Wenn das klappt, dann:

ping -c 3 9.9.9.9

Danach:

ping -c 3 heise.de

Erst wenn alle 3 Tests funktionieren, ist Schritt 2 erledigt.
Auf dem dns2 machen wir exakt dasselbe nur mit der 192.168.1.4.


Schritt 3: Unbound. Was ein Resolver ist (und warum wir ihn brauchen)

Jetzt kommt der erste Punkt, an dem man sich fragen kann:

„Warum der ganze Aufwand? Pi-hole kann doch DNS.“

Ja. Aber Pi-hole ist kein Resolver, sondern "nur" ein ausgezeichneter Filter.

Kurz gesagt:

Pi-hole entscheidet, ob eine Anfrage erlaubt ist, Unbound entscheidet, woher die Antwort kommt.

Wenn du Pi-hole direkt auf Google, Cloudflare oder deinen ISP zeigen lässt, hast du diverse Abhängigkeiten, keine echte Kontrolle, keinen klaren Trennstrich.

Ein Fallback zu Google DNS ist kein Sicherheitsnetz. Es ist eine Kapitulation.

Unbound macht dich souverän. Der Name ist Programm.


Installation

Auf beiden DNS-Servern:

sudo apt update &&
sudo apt install -y unbound unbound-anchor`

Warum Unbound nicht auf Port 53 läuft

Port 53 gehört später Pi-hole. Unbound läuft lokal, versteckt, auf Port 5335.
Das ist Absicht. Keine Clients sprechen direkt mit Unbound. Pi-hole ist der einzige Zugang.


Konfigurationsdatei anlegen

sudo nano /etc/unbound/unbound.conf.d/pi-hole.conf

Inhalt:

server:
	interface: 127.0.0.1
	port: 5335
	do-ip4: yes
	do-udp: yes
	do-tcp: yes
	
	hide-identity: yes
	hide-version: yes
	
	access-control: 127.0.0.0/8 allow  
	
forward-zone:
	name: "."
	forward-addr: 9.9.9.9
	forward-addr: 149.112.112.112`

Was bedeutet das nun genau?

  • 127.0.0.1 Nur dieser Rechner darf fragen.
  • port 5335 Kollisionsfrei mit Pi-hole.
  • forward-zone "." „Alles, was ich nicht selbst weiß, frage bei folgendem DNS-Anbieter.“

Ich nutze Quad9, weil europäisch/schweizerisch, datenschutzfokussiert, perfekte Malware-Filter.


Mein nächster Stolperstein: Trust Anchor

Unbound braucht eine Root-Vertrauensbasis. Manchmal ist die doppelt konfiguriert. Wie bei mir.

Wenn Unbound also nicht startet, prüfe:

grep -R "trust-anchor\|auto-trust-anchor-file" \ /etc/unbound/unbound.conf /etc/unbound/unbound.conf.d/* 2>/dev/null`

Wenn du zwei Treffer siehst, einen entfernen.


Initialisierung & Start

sudo unbound-anchor -a /var/lib/unbound/root.key 
sudo chown unbound:unbound /var/lib/unbound/root.key 
sudo chmod 0644 /var/lib/unbound/root.key  

sudo unbound-checkconf 
sudo systemctl enable --now unbound

Test (wie immer sehr wichtig)

dig @127.0.0.1 -p 5335 heise.de

Wenn du eine Antwort bekommst läuft Unbound, Dein DNS funktioniert unddu kannst weitermachen. Yeah!

Wenn nicht: Nicht mit Pi-hole anfangen. Erst hier reparieren.


Schritt 4: Pi-hole – und warum die GUI dich anlügt (nicht absichtlich, aber zuverlässig)

Jetzt kommt der Punkt, an dem viele Anleitungen wieder fröhlich sagen:
„Installiere Pi-hole, klick dich durch den Wizard, fertig.“

Und ja:
Pi-hole lässt sich leicht installieren und Pi-hole lässt sich extrem leicht falsch betreiben.

Die GUI ist freundlich. Die Defaults wirken plausibel. Und genau deshalb ist Pi-hole gefährlich für Menschen wie uns.


Was Pi-hole ist – und was nicht

Bevor wir irgendetwas installieren, eine Klarstellung:

Pi-hole ist kein DNS-Server im klassischen Sinn. Pi-hole ist ein DNS-Filter. Damit entscheidet Pi-hole Fragen wie: Darf diese Anfrage raus? Oder blocke ich sie?

Pi-hole löst nicht selbst rekursiv auf. Das macht Unbound, den wir im letzten Schritt gebaut haben.

Warum doch gleich noch mal so kompliziert? Wenn du das nicht trennst, wirst du später Logs nicht verstehen, Reverse DNS hassen und bei Fehlern nicht wissen, wo du suchen musst.


Installation: ja, das ist der einfache Teil

Auf dns1 (und dann identisch auf dns2 - ich habs in 2 Fenstern parallel gemacht):

curl -sSL https://install.pi-hole.net | bash

Der Installer ist textbasiert, interaktiv, (erinnert an Borlands Turbo Vision, kennt das noch jemand?). Und voll von Entscheidungen, die man falsch treffen kann. Ich gehe sie eine nach der anderen durch.

So sah das damals aus ... und für Text-"Grafik" ist das heute noch unschlagbar.

Installer-Schritt für Installer-Schritt

1. Netzwerkschnittstelle

Q: „Which interface should Pi-hole use?“
A: eth0

Warum? Das ist dein LAN. No network magic. Keine VLAN-Spielchen (bei mir noch nicht)


2. Upstream DNS Server – hier beginnt der Ärger

Pi-hole zeigt dir jetzt:

  • Google
  • Cloudflare
  • OpenDNS
  • Quad9
  • Custom
    Ja, wir wollen langfristig Quad9, trotzdem hier niemals einfach etwas anhaken.

A: Custom**
Dann trägst du exakt ein: 127.0.0.1#5335
Warum? 127.0.0.1 ist der lokale Rechner, #5335 → der Port, auf dem Unbound lauscht
Damit erzwingen wir: Alle DNS-Anfragen laufen: Client → Pi-hole → Unbound → Internet
Wenn du hier Google auswählst, hebelst du deine gesamte Souveränität wieder aus.


3. Blocklists

A: Yes
Wir wollen Pi-hole ja genau deshalb.


4. Query Logging

A: Yes
Wichtig, gerade am Anfang. Warum? Du wirst Dinge debuggen. Du willst sehen, wer fragt was und Du willst später verstehen, warum etwas blockiert wurde. Datenschutzdiskussionen führen wir nachdem es funktioniert. Oder im Heimnetzwerk etwas laxer sehen :-)


5. Privacy Mode

A: Level 0
Das ist absichtlich. Level 0 heißt volle Sichtbarkeit, maximale Transparenz, kein Rätselraten. Später kannst du das bei Bedarf härter drehen.


6. Web Interface & Web Server

A:Beides Yes
Du willst das Dashboard, die Logs, all die schicken Statistiken.


7. Passwort merken!

Pi-hole zeigt dir jetzt ein Admin-Passwort an.

Mach einenScreenshot. Oder aufschreiben. Nicht ignorieren. Screenshot ist sicherer.

Danach kannst (und solltest) du es ändern:

sudo pihole setpassword

Nein, bitte nicht dein Ubuntu-User-Passwort verwenden.


Der erste (falsche) Eindruck: „Es läuft doch!“

Nach der Installation sagt Pi-hole: „Pi-hole blocking is enabled“

Und tatsächlich, die Webseiten laden, Werbung ist weg,alles scheint gut zu sein
Jetzt bitte einmal innehalten. Pi-hole läuft. Aber noch völlig falsch für unser Ziel.


Der wichtigste GUI-Schritt (den fast jeder übersieht)

Einmal bitte auf die Weboberfläche ...

http://192.168.1.3/admin

... und Login mit dem gesetzten Passwort.

Gehe zu:

Settings → DNS
Jetzt kommt der Punkt, an dem die GUI dich anlügt. Oder zumindest etwas weglässt.


Upstream DNS Server (oberer Bereich)

Du siehst:

  • Google
  • Cloudflare
  • OpenDNS
  • Quad9
  • etc.

Nimm ALLE HÄKCHEN RAUS.

Warum? Weil Pi-hole sonst (parallel zu Unbound) externe Resolver fragt und du nie sicher bist, woher Antworten kommen.


Custom DNS Servers (unterer Bereich)

Hier muss stehen: 127.0.0.1#5335

Und nur das. Kein zweiter Eintrag. Kein Fallback. Keine „für alle Fälle“-DNS.

Merksatz:

Ein Fallback-DNS ist kein Backup, sondern ein Bypass.

Interface Settings

Hier bitte bewusst wählen:
Allow only local requests

Warum? Pi-hole beantwortet Anfragen aus deinem LAN, nicht aus dem Internet, nicht aus fremden Netzen. Wir wollen doch keine Türen in finstere fremde Dimensionen öffnen ...


Speichern & Neustart

Nach Änderungen:

pihole restartdns

4.1: Test - Funktioniert Pi-hole überhaupt?

Auf dns1 selbst:

dig heise.de

Wenn du eine Antwort bekommst: Pi-hole → Unbound → Internet funktioniert.
Wenn nicht: Nicht weitermachen. Fixen!


4.2: Dashboard-Check: Siehst du Queries im Dashboard?

Öffne das Dashboard. Du solltest Queries, Domains, Clients (wenn auch nur bisher IP's) sehen.
Wenn hier nichts auftaucht, wird Pi-hole nicht genutzt oder oder lauscht nicht korrekt.


Warum wir hier noch keinen Client anschließen

Bis hierhin haben wir erreicht dass

  • Pi-hole läuft,
  • Unbound läuft und
  • DNS funktioniert
  • Webseiten laden ohne Werbung

Schön. Aber:

  • Namen sind noch nicht sauber
  • Reverse DNS fehlt
  • Hochverfügbarkeit fehlt
  • Failover fehlt

Wenn wir jetzt schon Clients auf Pi-hole schicken sammeln wir Logs, die später wertlos sind, verunsichern bei Fehlern und erschweren das Debugging

Deshalb: Erst das Fundament fertiggiessen, dann folgt der Straßenverkehr.


Schritt 5: Reverse DNS, PTR & der pi.hole-Fluch

(oder: Warum Logs ohne Namen dich langsam wahnsinnig machen)

Irgendwas passt noch nicht. Spätestens dann, wenn du ins Pi-hole-Dashboard schaust, siehst Du es. Oder eben nur ...

Das erste Symptom: „Warum sehe ich nur IP-Adressen?“

Im Dashboard siehst du: 192.168.1.23, 192.168.1.42, 192.168.1.101 aber keine Namen.

Oder noch schlimmer wie in meinem Fall. Plötzlich taucht überall pi.hole auf, also bei Reverse Lookups, in Logs und in Tools wie nslookup. Hier habe ich die längste und frustrierendste Zeit verbracht.

Das ist der Moment, in dem viele denken: „Ach egal, Hauptsache es geht.“
Tu dir selbst einen Gefallen: Nein.


Warum Reverse DNS hier entscheidend ist

Reverse DNS beantwortet nicht: „Wie heißt google.com?“ sondern „Wer bist du eigentlich?“

Also:
Wer steckt hinter 192.168.1.3?
Welcher Server antwortet gerade?
Welcher Client fragt hier ständig Unsinn?

Ohne Reverse DNS sind Logs sind anonym, Debugging ist mühsam, Hochverfügbarkeit ist nicht nachvollziehbar.
Mit Reverse DNS dagegen erkennst du sofort, wer was tut, Du siehst im Failover, welcher Node aktiv ist und die werden Dashboards endlich lesbar.


Was wir erreichen wollen

Diese Tests sollen und müssen alle funktionieren:

nslookup dns1.pandolin.online 192.168.1.3 
nslookup 192.168.1.3 192.168.1.3````

Erwartung:

- Forward:  `dns1.pandolin.online → 192.168.1.3`
- Reverse:  `192.168.1.3 → dns1.pandolin.online`

**Und nirgendwo darf/soll `pi.hole` auftauchen.**

___
## Schritt 5.1: Lokale DNS-Records in Pi-hole setzen

Das machen wir **bewusst zuerst über die GUI**.
#### Öffne die Pi-hole Web-Oberfläche
 ````nginx
 http://192.168.1.3/admin

Gehe zu:

Local DNS → DNS Records und trage ein:

Domain IP
dns1.pandolin.online 192.168.1.3
dns2.pandolin.online 192.168.1.4
Und ... speichern.

Test! (Forward DNS)

Auf dns1:

nslookup dns1.pandolin.online 192.168.1.3

Wenn du jetzt keine Antwort bekommst, dann die übliche Runde. Tippfehler prüfen und nicht weitermachen bevor alles klappt.


Schritt 5.2: PTR Records (Reverse DNS) setzen

Jetzt der Teil, den viele übersehen.

In der Pi-hole GUI:

Local DNS → PTR Records

IP Hostname
192.168.1.3 dns1.pandolin.online
192.168.1.4 dns2.pandolin.online

Und nochmal ... speichern.


Test! (Reverse DNS)

nslookup 192.168.1.3 192.168.1.3

Jetzt kommt der Moment Deiner Wahrheit.


Wenn jetzt pi.hole zurückkommt: Willkommen im Fluch

Wie bei mir. Sehr wahrscheinlich siehst du immer noch Name: pi.hole
Oder Pi-hole taucht in Logs auf, obwohl du alles korrekt eingetragen hast.

Du hast nichts falsch gemacht. Das ist ein Default-Verhalten von Pi-hole, das nicht über die GUI steuerbar ist. Und genau hier scheitern die meisten Anleitungen.
Ich glaube das waren bei mir 2 Stunden und 4 Tassen Kaffee.


Die eigentliche Ursache (endlich erklärt)

Pi-hole hat intern eine Einstellung: „Was soll ich als PTR-Namen zurückgeben, wenn ich selbst angesprochen werde?“
Standardantwort: PI.HOLE

Egal, was du in der GUI einträgst. Das ist historisch gewachsen, schlecht bis gar nicht dokumentiert und war für mich extrem verwirrend.


Die Lösung liegt nicht in der GUI

Sie liegt in einer Datei, die kaum erwähnt wird: /etc/pihole/pihole.toml


Schritt 5.3: Der entscheidende Fix (piholePTR)

Auf dns1:

sudo nano /etc/pihole/pihole.toml

Suche nach piholePTR. Wenn der Eintrag nicht existiert, füge ihn hinzu.
Setze exakt:

piholePTR = "HOSTNAMEFQDN"

Ganz wichtig:
Nicht
dns1.pandolin.online.
Nicht PI.HOLE
Nicht irgendetwas „logisches“

Sondern genau dieser String. Warum? Weil Pi-hole sich daraus automatisch den FQDN des Systems zieht. Trägst du hier etwas anderes ein, fällt Pi-hole stumm auf PI.HOLE zurück.

Dienst neu starten

sudo systemctl restart pihole-FTL`

Tests (jetzt zur Abwechselung bitte alle!)

Auf dns1:

nslookup 192.168.1.3 192.168.1.3 
nslookup dns1.pandolin.online 192.168.1.3

Und vom Client (explizit):

nslookup google.com 192.168.1.3 
nslookup 192.168.1.3 192.168.1.3`

Erwartung ist nun kein pi.hole, nur echte Namen, Logs werden lesbar.


Warum das so wichtig war (und keine reine Kosmetik)

Ohne diesen Fix sehen wir im Failover nicht, welcher Node aktiv ist, sehen Logs aus wie anonymisierte Unfallberichte, baust Du Frust auf, verlierst du Vertrauen in dein eigenes Setup.

Mit diesem Fix erkennen wir DNS-Flüsse sofort, können Probleme einordnen und baust auf einer sauberen Identität auf.


Schritt 6: Hochverfügbarkeit, virtuelle IP

… und warum plötzlich alles kaputt ist, obwohl nichts kaputt ist

Bis hierher haben wir zwei funktionierende DNS-Server. Saubere Namen (Forward & Reverse). Pi-hole + Unbound laufen stabil. Schwer genug wars.

Was wir noch nicht haben, ist Hochverfügbarkeit. Wir habenzwei Server, aber noch keine gemeinsame Identität.

Das Kernproblem ist, ein Client (PC, Handy, Fernseher, etc) merkt sich eine DNS-Adresse und erwartet, dass diese immer antwortet. Er interessiert sich nicht dafür, warum sie gerade nicht antwortet. Wenn wir ihm nun zwei DNS-Adressen geben ist das keine Redundanz sondern eine Einladung zum unkontrollierten Chaos

Was wir brauchen, ist eine Adresse, die immer existiert. Egal, welcher Server dahinter steht.
Jetzt sind wir endlich bei der VIP angekommen, der virtuellen IP.


Das Ziel dieser Etappe wird sein ...

Alle Clients sprechen nur mit 192.168.1.5. Diese IP gehört immer genau einem Server, Wenn dieser Server ausfällt:

  • übernimmt der andere automatisch
  • ohne Umkonfiguration
  • ohne Client-Neustart
  • ohne jeden manuellen EIngriff

Wie das technisch funktioniert?

Wir nutzen keepalived. Damit nutzen wir nutzt das VRRP-Protokoll. Das lässt Server untereinander sagen: „Lebst du noch?“ und anhand von Priorität + Gesundheitszustand entscheidet es dann wer die virtuelle IP tragen darf.
Wichtig: keepalived prüft nicht automatisch, ob DNS funktioniert. Das müssen wir ihm beibringen.


Schritt 6.1: keepalived installieren

Auf dns1 und dns2:

sudo apt update &&
sudo apt install -y keepalived

Noch passiert gar nichts. keepalived läuft noch nicht.


Schritt 6.2: Der Healthcheck – ohne den ist alles sinnlos

Das ist einer der wichtigsten Punkte. Wenn wir keepalived nicht sagen, wann DNS „gesund“ ist, passiert Folgendes: Ein Server kann tot sein, keepalived hält trotzdem die VIP. Die Clients laufen ins Leere und wir denke uns "Was für ein komplizierter Mist. Von wegen VIP."

Das ist kein Bug, das ist fehlende Information.


Wir bauen einen eigenen DNS-Gesundheitstest

Auf beiden Servern:

sudo nano /usr/local/bin/check_dns.sh

Inhalt bitte komplett einkopieren:

#!/bin/bash 
# Prüft, ob DNS lokal antwortet. 
# Wenn nicht -> keepalived gibt die VIP ab.  

dig +time=1 +tries=1 @127.0.0.1 google.com >/dev/null 2>&1 
exit $?`

Was passiert hier? Wir fragen lokal DNS ab, nicht über das Netzwerk, nicht über die VIP. Wenn das fehlschlägt ist unser DNS kaputt.

Jetzt ausführbar machen:

sudo chmod +x /usr/local/bin/check_dns.sh

Schritt 6.3: keepalived konfigurieren (dns1 = Master)

Jetzt kommt die erste Konfigurationsdatei.

Auf dns1:

sudo nano /etc/keepalived/keepalived.conf

Kompletter Inhalt:

vrrp_script chk_dns {
	script "/usr/local/bin/check_dns.sh"
	interval 2
	fall 2
	rise 2
	timeout 2
}

vrrp_instance DNS_VIP {
	state MASTER
	interface eth0
	virtual_router_id 51
	priority 150
	advert_int 1
	authentication {
			auth_type PASS
			auth_pass supersecret
     }
     
     virtual_ipaddress {
              192.168.1.5/24
     }
     
     track_script {
              chk_dns
     }
 } 

Was du hier wichtig ist : priority 150 bedeutet dns1 ist bevorzugt. Die virtual_router_id muss auf beiden gleich sein. Dastrack_script, das ist der Healthcheck. Die IP 192.168.1.5 ist unsere VIP.


Schritt 6.4: keepalived konfigurieren (dns2 = Backup)

Auf dns2:

sudo nano /etc/keepalived/keepalived.conf`

Inhalt:

vrrp_script chk_dns {
	script "/usr/local/bin/check_dns.sh"
	interval 2
	fall 2
	rise 2
	timeout 2
}

vrrp_instance DNS_VIP {
	state BACKUP
	interface eth0
	virtual_router_id 51
	priority 100
	advert_int 1
	authentication {
			auth_type PASS
			auth_pass supersecret
     }
     
     virtual_ipaddress {
              192.168.1.5/24
     }
     
     track_script {
              chk_dns
     }
 } 

Deja vu? Einziger Unterschied: state BACKUP und eine niedrigere priority.


Schritt 6.5: keepalived starten

Auf beiden Servern:

sudo systemctl enable --now keepalived`

Jetzt prüfen:

ip a | grep 192.168.1.5`

Erwartung:
Auf dns1 siehst du: inet 192.168.1.5/24 scope global secondary eth0, auf auf dns2: nichts.
So weit so gut.


Und jetzt: der Moment, an dem plötzlich nichts mehr ging

Alles fertig. Dachte ich. Wenn ich jetzt jetzt auf einem Client testete:

nslookup google.com 192.168.1.5

bekam ich den berühnten
DNS request timed out.

Und das obwohl die VIP existiert, der- Pi-hole läuft, keepalived läuft und alles andere auch korrekt aussieht.
In dem Moment, das war so gegen 2 Uhr nachts, habe ich Pi-hole verflucht, habe überlegt ob ich alles hinwerfen will oder anfange neu zu installieren. Ich habs nicht getan. Und im Gegensatz zu Windows kann man bei Linux immer alles reparieren!


Das Problem ist NICHT DNS. Es ist ARP.

Die Kurzfassung ist: Netzwerke merken sich „Welche MAC-Adresse gehört zu welcher IP?“
Diese Zuordnung wird gecached.
UniFi-Geräte und Windows sind hier besonders… selbstbewusst.
Wenn die VIP neu erscheint erkennt der Client das nicht zuverlässig,
Anfragen landen im Nirwana, Tiimeouts kommen und mein DNS wirkt „kaputt“, ist es aber nicht.


Die Lösung: Aggressives Gratuitous ARP (GARP)

Wir müssen keepalived mitgeben: „Sag dem Netzwerk mehrfach und möglichst laut, dass diese IP jetzt hier wohnt.“


Schritt 6.6: ARP-Fix in keepalived

Auf beiden Servern in der conf Datei ergänzen.:

sudo nano /etc/keepalived/keepalived.conf`
vrrp_script chk_dns {
	script "/usr/local/bin/check_dns.sh"
	interval 2
	fall 2
	rise 2
	timeout 2
}

vrrp_instance DNS_VIP {
	state BACKUP
	interface eth0
	virtual_router_id 51
	priority 100
	advert_int 1
	
	garp_master_delay 1
	garp_master_repeat 5
	garp_master_refresh 10
	garp_master_refresh_repeat 2

	authentication {
			auth_type PASS
			auth_pass supersecret
     }
     
     virtual_ipaddress {
              192.168.1.5/24
     }
     
     track_script {
              chk_dns
     }
 } 

Danach auf beiden:

sudo systemctl restart keepalived

WICHTIG: Client-Cache leeren (sonst lügt er)

Auf Windows (als Administrator) arp -d * ipconfig /flushdns und danach erneut testen:
nslookup google.com 192.168.1.5
Wenn jetzt eine Antwort kommt: Yes. You did it!

Der eigentliche Aha-Moment: Bis hierhin war alles richtig konfiguriert. Der Fehler war nicht logisch, sondern physikalisch. Das Netzwerk wusste nicht, wo diese IP eigentlich lebt.


Schritt 7: Tests, Failover & die DreamWall

… oder: Wann man endlich aufhören darf, alles zu hinterfragen

Wir haben jetzt 2 DNS-Server (dns1, dns2) mit einer virtuellen IP (192.168.1.5). Pi-hole + Unbound laufen stabil. Reverse DNS sauber. keepalived läuft mit Healthcheck. Meine ARP-Probleme sind final geklärt.
Alles fertig?
Jetzt müssen wir beweisen, dass das Ganze nicht nur theoretisch, sondern praktisch hochverfügbar ist. Eine letzte ...


Wichtige Teststrategie!

Wir testen bewusst in Stufen:

  1. Direkt gegen die VIP
  2. Vom Client, ohne DHCP
  3. Vom Client, mit DHCP
  4. Failover unter Last
  5. Rückkehr des Masters

Wenn ein Test fehlschlägt, wie immer, nicht weiter. Ursache klären, Fehler beseitigen.


Test 7.1: Direkter Test gegen die virtuelle IP

Auf irgendeinem Rechner im LAN (oder dns1 selbst):
nslookup heise.de 192.168.1.5

Erwartung:

  • schnelle Antwort, ohne Timeout

Dann:
nslookup 192.168.1.5 192.168.1.5
Entscheidend hier ist weniger das Ergebis aber keine Hänger, keine Timeouts.

Wenn das nicht funktioniert heisst es den ARP-Cache prüfen, ip a auf dns1/dns2 prüfen und den keepalived-Status checken-


Test 7.2: Client-Test ohne DNS der Dreamwall (kontrolliert!)

Bevor wir an die DreamWall und das Fundament unserer Welt umbauen gehen, testen wir gezielt einen Client.

Beispiel: Windows

Netzwerkeinstellungen:

  • IP: automatisch
  • DNS: manuell 192.168.1.5

Dann:
nslookup heise.de

Danach im Browser:

  • ein paar normale Webseiten
  • ein paar Seiten mit viel Werbung wie Chip oder ähnlich
  • Pi-hole Dashboard beobachten

Jetzt sollten:

  • Queries beim Pi-hole reinkommen
  • Clients erscheinen
  • Namen sind sauber

Wenn das unwahrscheinlicherweise nicht funktioniert: Nicht an der DreamWall drehen.


Test 7.3: Der eigentliche Härtetest – Failover

Jetzt kommt der Teil, für den wir das alles gebaut haben. The final hour!

Variante A: Dienst stoppen (sauber)

Auf dns1:
sudo systemctl stop pihole-FTL

Was jetzt passieren sollte ist dass der check_dns.sh fehlschlägt. Damit senkt keepalived senkt die Priorität und VIP 192.168.1.5 wandert zu dns2.

Prüfen wir das mit ip a | grep 192.168.1.5. Auf dns2 sollte sie jetzt erscheinen.


Variante B: Brutaltest (Stecker ziehen)

Ja. Wirklich. Der Asteroid ist eingeschlagen. Oder das Kind hat am Stecker gespielt. Netzwerkkabel raus oder oder Maschine ausschalten. Bei den Blades ist es wegen PoE das selbe.

Wenn dein Client jetzt weiter surfen kann, keine DNS-Ausfälle zeigt und das Pi-hole-Dashboard auf dns2 weiterläuft besteht unser Failover.


Test 7.4: Rückkehr des Masters

Jetzt dns1 wieder starten:

sudo systemctl start pihole-FTL

Nach kurzer Zeit gewinnt dns1 wieder wegen höherer Priorität, die VIP wandert zurück und dns2 hält sich wieder bereit im Hintergrund. Kontrollierter Wechsel. Ziel erreicht.


Schritt 8 (final): DNS-Verteilung über die UniFi Dream Wall

Ziel:
Alle Clients im Netz nutzen direkt deine hochverfügbare VIP. Die Dream Wall bleibt DHCP-Server. Aber wir zwingen sie dazu, nicht sich selbst als DNS anzubieten, sondern direkt unsere VIP 192.168.1.5 an die Clients zu verteilen.

Warum?
Damit sprechen alle Clients direkt mit unserem Cluster. So sehen wir im Pi-hole Dashboard genau, welches Gerät (TV, Handy, Laptop) welche Anfrage stellt, anstatt dass alles anonym über den Router läuft.


Da muss ich doch noch was einstellen ...

UniFi Network → Networks → Default
DHCP Mode
DHCP Server (bleibt an)
DHCP Relay (aus)

Warum? Die Dream Wall bleibt der einzige DHCP-Master. Pi-hole macht kein DHCP. Punkt.


DNS-Einstellungen im Netzwerk

❌ Auto DNS Server → AUS
✅ Manuelle DNS Server → AN

IPv4 DNS Server: 192.168.1.5
KEIN zweiter DNS
KEIN 8.8.8.8
KEIN 9.9.9.9

Warum so strikt? Mehrere DNS = Clients entscheiden selbst. Clients failovern nicht sauber. Debugging wird unmöglich. Eine VIP ist der Kontrollpunkt. Redundanz passiert hinter dieser IP, nicht davor.


Domain Name (optional, aber empfohlen)
Domain Name: pandolin.online

Warum? Für saubere FQDNs im Netz, konsistente Logs, gleiche Namen intern & extern.


Fazit

Das war ein richtig langer und harter, manchmal trockener Ritt.
Ich bin für euch in jeden Rechen getreten, der im hohen Gras lag.
Was hier steht, ist kein Bastelprojekt mehr.

Es ist:

  • souverän
  • redundant
  • debugbar
  • stabil
  • und irgendwie langweilig.

Und genau so muss Infrastruktur sein.
Langweilig.
Belastbar.
Nicht der Maserati sondern der VW Passat, der seine 350.000 Kilometer ohne Mucken fährt.

Happy Digital Independence Day 🐧


P.S. Wer hat so lange durchgehalten? Dann ist es Dir vielleicht aufgefallen, NTP habe ich nicht mehr geschafft. Folgt beim nächsten Mal.

Subscribe to pandolin.io

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe