Der 35-Watt-Mitbewohner (Teil 6): Werbung? Kenne ich nicht.
In Teil 1 habe ich den Lenovo M920q als Compute-Knoten eingerichtet. Teil 2 drehte sich um die sichere Anbindung ans Internet. Jetzt wird’s Zeit, dass der kleine Homeserver auch was fürs tägliche Wohlbefinden tut: Werbung killen.
Das Ziel: Netzwerkweite Ruhe
Werbung im Internet nervt. Auf dem Handy, auf dem Smart-TV, überall. Die Lösung für jeden Homeserver-Besitzer ist klar: Ein netzwerkweiter DNS-Blocker. Lange Zeit war Pi-hole der Platzhirsch, aber ich habe mich für AdGuard Home entschieden. Es wirkt moderner, unterstützt DNS-over-HTTPS/TLS von Haus aus und die Oberfläche gefällt mir einfach besser.
Klingt einfach, oder? Container starten, fertig. Oh, wie naiv ich war.
Der Endgegner: Port 53
Der erste Versuch, den Container im host Netzwerk zu starten, scheiterte sofort. Der Grund: Port 53.
Dieser Port ist der Standard für DNS-Anfragen. Auf fast jedem modernen Linux-Server (wie meinem Ubuntu-Host) wird dieser Port bereits vom Systemdienst systemd-resolved belegt. Der Container konnte nicht starten.
Klar, ich hätte einfach systemd-resolved deaktivieren können. Aber tief im Host-System herumzudoktern widerspricht meiner Philosophie: Der Docker-Host soll so vanilla wie möglich bleiben. Also: Plan B.
Die elegante Lösung: Macvlan
Ein Macvlan-Netzwerk in Docker ist genial. Es erlaubt dem Container, sich wie ein echtes, physisches Gerät im Netzwerk zu verhalten. Er bekommt seine eigene MAC-Adresse und viel wichtiger seine eigene IP vom Router, völlig unabhängig vom Host-Server.
Das bedeutet: Kein Port-Konflikt mehr auf Port 53!
Da mein Netzwerk Dual-Stack-fähig ist, wollte ich es richtig machen. Der Container bekommt sowohl eine feste IPv4 (192.168.50.250) als auch eine feste IPv6 (eine stabile ULA-Adresse, beginnend mit fd...). Zukunftssicher.
Die nächste Baustelle: Traefik
Der DNS-Blocker lief jetzt, aber ich wollte Zugriff auf das Web-Dashboard über meine sichere Domain (adguard.dieck-labs.de) via Traefik Reverse Proxy. Keine IP-Adressen mehr eintippen wie ein Höhlenmensch.
Hier wurde es knifflig.
Problem 1: Netzwerk-Isolation
Damit Traefik den Container erreichen kann, müssen beide im selben internen Docker-Netzwerk sein (bei mir apps). Aber wenn AdGuard im Macvlan hängt, ist es isoliert vom Rest der Docker-Welt.
Die Lösung: Der Container muss Mitglied in beiden Netzwerken sein. Macvlan fürs Heimnetz, apps für Traefik.
Problem 2: Das 502-Bad-Gateway-Drama
Nach der Traefik-Integration: Fehlermeldungen. 502 Bad Gateway. Stundenlange Fehlersuche.
Des Rätsels Lösung: Wenn man AdGuard Home initial über die Macvlan-IP einrichtet, konfiguriert es sich so, dass es nur auf dieser spezifischen IP lauscht. Anfragen von Traefik aus dem internen apps-Netzwerk? Werden ignoriert.
Der Fix: In der AdGuardHome.yaml musste ich die Binding-Adresse auf 0.0.0.0 setzen (alle Interfaces) und das Web-UI auf einen unüblichen Port wie 8087 legen. So kann Traefik sauber zugreifen, während DNS weiterhin auf Port 53 läuft.
Die Architektur
So sieht der Datenfluss jetzt aus:
Die config: Zwei Netzwerke, ein Container
Und hier ist das finale Docker Compose File (adguard.yml im Repo). Das Resultat von zu vielen Abenden vor dem Terminal:
version: "3.9"
services:
adguardhome:
image: adguard/adguardhome:latest
container_name: adguardhome
restart: unless-stopped
networks:
# Netzwerk 1: Für DNS-Anfragen aus dem Heimnetz
macvlan_net:
ipv4_address: 192.168.50.250
ipv6_address: fd15:d91c:273f:0::250
# Netzwerk 2: Für die Kommunikation mit Traefik
apps:
volumes:
# Docker verwaltet die Arbeitsdaten (Logs etc.)
- adguard_work:/opt/adguardhome/work
# WICHTIG: Lokaler Bind-Mount für die Config
- ./adguard:/opt/adguardhome/conf
labels:
- "traefik.enable=true"
- "traefik.docker.network=apps"
- "traefik.http.routers.adguard.rule=Host(`adguard.dieck-labs.de`)"
- "traefik.http.routers.adguard.entrypoints=websecure"
- "traefik.http.routers.adguard.tls.certresolver=myresolver"
# Traefik kommuniziert intern über diesen Custom-Port
- "traefik.http.services.adguard.loadbalancer.server.port=8087"
networks:
macvlan_net:
driver: macvlan
enable_ipv6: true
driver_opts:
parent: ens18 # Das physische Interface des Servers
ipam:
config:
- subnet: 192.168.50.0/24
gateway: 192.168.50.1
- subnet: fd15:d91c:273f:0::/64
gateway: fd15:d91c:273f:0::1
apps:
external: true # Das existierende Traefik-Netzwerk
volumes:
adguard_work:
external: true
Der Config-Trick
Ein wichtiges Detail: Die AdGuardHome.yaml im ./adguard Ordner muss manuell angepasst werden:
http:
address: 0.0.0.0:8087 # Auf allen Interfaces lauschen
dns:
bind_hosts:
- 192.168.50.250
- "fd15:d91c:273f:0::250"
port: 53
Ich habe zuerst versucht, die Config über Docker configs einzubinden sehr elegant, “Infrastructure as Code” und so. Aber: Read-only. Das Dashboard konnte keine Änderungen mehr speichern. Der gute alte Bind-Mount war am Ende die pragmatischere Lösung.
Die Fritz!Box füttern
Ein netzwerkweiter Adblocker bringt nichts, wenn niemand ihn nutzt. Anstatt an jedem Gerät manuell die DNS-Einstellungen zu ändern, bringen wir der Fritz!Box bei, AdGuard als Standard-DNS an alle Geräte zu verteilen.
- Fritz!Box öffnen:
http://fritz.box→ Internet → Zugangsdaten → DNS-Server - DNSv4 eintragen: “Andere DNSv4-Server verwenden” aktivieren und
192.168.50.250als bevorzugten DNS-Server eintragen - DNSv6 eintragen: Falls gewünscht, auch die IPv6-Adresse (
fd15:d91c:273f:0::250) für DNSv6 hinterlegen - Geräte reconnecten: Am einfachsten WLAN kurz aus- und einschalten, damit die neuen DNS-Einstellungen gezogen werden

Das Ergebnis
Wenn ich jetzt im AdGuard-Dashboard auf das Anfragenprotokoll klicke, sehe ich live, wie Tracking-Domains ins digitale Nirvana geschickt werden.
Die YouTube-App auf dem Smart-TV lädt schneller (weniger Werbe-Requests), und das Gewissen ist auch beruhigt weniger Tracking bedeutet mehr Privatsphäre für alle im Haushalt.
Was ich gelernt habe:
- Macvlan ist die elegante Lösung für Port-Konflikte auf dem Host
- Zwei-Netzwerk-Setups in Docker erfordern sorgfältige Binding-Konfiguration
- Manchmal ist ein pragmatischer Bind-Mount besser als eine “saubere” read-only Config
Der kleine 35-Watt-Mitbewohner hat jetzt eine weitere Aufgabe: Türsteher fürs Heimnetz. In Teil 4 wird’s dann um Monitoring gehen denn was bringt ein Homelab, wenn man nicht ständig auf bunte Grafana-Dashboards starren kann?