con-pihole Projekt

Seit geraumer Zeit beschäftige ich mich mit dem DNS-Tool Pi-hole, welches ich zugegebenermaßen als sehr sinnvoll und ausgereift erachte. Es handelt sich dabei um einen lokalen Nameserver mit einer ganzen Armada an Filter- und Auswahloptionen um das heimische Netzwerk bestmöglich werbe- und trackerfrei zu halten – sicher wird diese Kurzbeschreibung dem wirklich mächtigen Tool nicht hinreichend gerecht, doch zur ersten Erklärung für diesen Beitrag soll es genügen.

Warum aber nenne ich mein Projekt nun „con-pihole“ ? Das ist ganz einfach, denn ich lasse meine Pi-hole Installation in einem Docker Container laufen. Grundlegend ist der Gedanke hinter dem Pi-hole Projekt, die Installation auf einem Raspberry PI zu etablieren, doch ich für meinen Teil habe ein Synology NAS ohnehin 7×24 aktiv, also wozu weitere Hardware anschaffen, wenn es auch virtuell geht 🙂

Da ich bei dem Versuch hier alles sauber in mein Netzwerk zu integrieren die letzten Monate über diverse Stolpersteine gefallen bin, im Internet auch nicht wirklich komplette Guides gefunden habe und ich ohnehin alles „irgendwie anders“ haben wollte – hier nun mein HowTo, um eine Pi-hole Installation im Docker Container auf einer Synology sauber zum Laufen zu bekommen.

Ach ja, grundlegend sind hier gelistete IP-Adressen sowie lokale Domainnamen für mein Lab gedacht und müssen logischerweise an die jeweilige Netzwerkumgebung angepasst werden – ich sage hier nur fritz.box 😉

Als erste Aktion wird auf dem Synology NAS das Docker Paket über das Paket-Zentrum im DSM installiert. Hier darauf achten, dass das NAS-Modell auch die Nutzung von Containern unterstützt – welches Modell dafür geeignet ist, beschreibt Synology auf seiner Webseite.

Nach der erfolgreichen Installation muss der SSH-Zugriff auf die Synology sichergestellt werden. Falls das nicht bereits der Fall ist, wird das über die Systemsteuerung aktiviert – der Standardport für den Service kann nach eigenen Wünschen angepasst oder eben auf dem Standard ( Port: 22 ) belassen werden.

Als Nächstes per SSH auf die Synology verbinden, um die grundlegende Netzkonfiguration anzulegen.

Ich habe mich hier, dank verfügbarem OVS, für ein Transfer-Netz über alle Container entschieden, was sich so leider nicht über die DSM-GUI erstellen lässt. Es ginge notfalls auch den Container per NAT erreichbar zu machen, doch dann müssten sich die Default-Portnunmmern des DNS-Service ( 53 und 853 ) ändern und das wollte ich vermeiden – dazu später noch weitere Details 🙂

Je nach physischer Netzwerkanbindung der Synology können sich die Interface-Bezeichnungen unterscheiden. In meinem Fall ist die Synology über einem LACP Bond angeschlossen, von daher meine Interfacebezeichnung in der weiteren Beschreibung „ovs_bond0“.

Weiterhin befindet sich meine Synology in meinem Lab in einem eigenen VLAN ( 192.168.1.0/24 ), in welches das Transfer-Netz nun kaskadiert eingebunden wird. An dieser Stelle sei den Super-Senior-Netzwerk-Admins ein virtueller Schlag auf meinen Schädel gegönnt, doch – ihr werdet es später noch lesen – für meine DNS- / DHCP-Einstellungen ist das der eleganteste, wenn sicher auch nicht der „technisch korrekteste“ Weg 🙂

Der Haken an eben diesem Aufbau ist, dass der für dieses VLAN zuständige DHCP-Server das kaskadierte Subnetz aus seiner Zuteilungsliste gestrichen bekommen muss – potentiell doppelte IP-Vergabe. In diesem VLAN also die DHCP-Range sicherheitshalber auf 192.168.1.6 – 192.168.1.150 begrenzen.

Jetzt aber wirklich ab in die Shell und folgenden Befehl absetzen

docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 --ip-range=192.168.1.200/29 --aux-address "host=192.168.1.201" -o parent=ovs_bond0 macvlan-if0 

Das Ergebnis sollte dann ein, für alle Container bereitstehendes virtuelles Netzwerk sein, inklusive einer entsprechenden Host-Gateway-Adresse ( hier: 192.168.1.201 ). Diese Host-Gateway-Adresse ist wichtig, damit Host ( Synology ) und Container entsprechend miteinander kommunizieren können, ansonsten wäre bei der späteren DNS-Konfiguration die Synology nicht mehr in der Lage eine Namensauflösung zu nutzen 😉

root@synology:~# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
ec4648f18f6e        bridge              bridge              local
e2b570b28f26        host                host                local
6e777b271586        macvlan-if0         macvlan             local
1081e1b30f52        none                null                local

Die DSM-GUI im Docker-Paket sollte diese Konfiguration bestätigen:

Die besagte Gateway-Adresse dieses Netzwerks muss nun noch mit einer Route versehen und an ein Interface auf dem Host gebunden werden. Dazu sind die folgenden vier Kommandos via Shell zu verwenden.

ip link add macvlan-b0 link ovs_bond0 type macvlan mode bridge
ip addr add 192.168.1.201/32 dev macvlan-b0
ip link set macvlan-b0 up
ip route add 192.168.1.200/29 dev macvlan-b0

Da diese Einstellung auf der Synology nicht persistent ist, sprich nach einem Neustart verschwindet, habe ich im Aufgabenplaner des DSM einen Task hinterlegt, welcher jede Minute validiert, ob die Interface-Einstellungen gesetzt sind und diese gegebenenfalls neu einträgt.

# Create macvlan Host-Bridge
# Checkscript, run every minute
#
if ! ip r | grep -q "192.168.1.200/29 dev macvlan-b0"; then
    ip link add macvlan-b0 link ovs_bond0 type macvlan mode bridge
    ip addr add 192.168.1.201/32 dev macvlan-b0
    ip link set macvlan-b0 up
    ip route add 192.168.1.200/29 dev macvlan-b0
fi

Da nun die gesamten Netzwerkeinstellungen erledigt sind, geht es an die Vorbereitung zur eigentlichen Containererstellung. Hierzu muss erst einmal über die Registry im Docker-Paket das entsprechende Image heruntergeladen werden. In diesem Fall eben das offizielle Pi-hole Image in der letzten stable-Version ( latest ).

Spätestens ab hier könnte ich nun alles schön automatisiert laufen lassen oder mich beispielsweise mit docker-compose vergnügen, doch ich möchte das restlich Folgende gerne schrittweise und „von Hand“ erledigen 🙂

Somit also über die Shell erst einmal die Parameterdatei anlegen. In diesem File ( in meinem Beispiel env.txt ) werden die Containerparameter, welche für ein sauberes Deployment benötigt werden, eingetragen. Ich habe mich in meinem Fall dafür entschieden, die Aufgaben eines DHCP-Servers nicht in die Hände des Pi-hole zu legen, auch wenn dieser das ebenfalls abbilden könnte, daher ist die Aktivierung als auch Konfiguration von Conditional-Forwarding relevant. Weiterhin habe ich einen fest definierten Forward-DNS-Server im Internet gewählt, welcher neben hinreichend geringer Latenz auch noch DNSSEC unterstützt. IPv6 möchte ich nicht verwenden und die User- als auch Gruppen-ID des Synology-Users sollte dem Container bekannt gemacht werden.

Das Ganze sieht dann so aus:

root@synology:~# pwd
/root
root@synology:~# ls
env.txt

Und der Inhalt des Files:

WEBPASSWORD=<Passwort für die Pi-hole GUI>
PUID=<UserID des Synology-Users>
PGID=<GroupID des Synology-Users>
TZ=Europe/Berlin 
ServerIP=192.168.1.202
IPv6=False
CONDITIONAL_FORWARDING_REVERSE=1.168.192.in-addr.arpa
CONDITIONAL_FORWARDING_DOMAIN=localnet
CONDITIONAL_FORWARDING=True
CONDITIONAL_FORWARDING_IP=192.168.1.1
DNSSEC=true
DNS1=1.1.1.1
DNS2=1.0.0.1

Jetzt kann der eigentliche Container angelegt werden. Dazu im gleichen Verzeichnis, in welchem die env.txt-Datei angelegt wurde, folgendes Kommando absetzen:

docker create --env-file env.txt --name=con-pihole --hostname=con-pihole --net=macvlan-if0 --ip=192.168.1.202 -it pihole/pihole:latest

Um nun auch nach einem Update oder Neustart des Containers nicht wichtige Einstellungen sowie Konfigurationen zu verlieren, mounte ich noch einige Files beziehungsweise Verzeichnisse an den Container – diese liegen lokal im Synology-Filesystem ( /volume1/docker/con-pihole), ausserhalb der eigentlichen Container-Struktur. In meinem Fall wie folgt:

root@synology:/volume1/docker/con-pihole# ls -al
total 8
drwxr-xr-x  1 syno_admin users   78 Aug  6 10:51 .
drwxr-xr-x  1 root       root    32 Oct 19 00:15 ..
drwxr-xr-x  1 syno_admin users   56 Oct 17 22:04 etc_dnsmasq.d
drwxr-xr-x  1 syno_admin users 3724 Oct 21 17:58 etc_pihole
-rw-rw-r--  1 syno_admin users   72 Aug  6 10:34 hosts
-rw-rw-r--  1 syno_admin users   70 Aug  6 10:34 resolv.conf

Theoretisch sollte das in dem oben gezeigten „docker create“ Kommando mit dem Parameter „-v“ ( optional auch –mount ) inkludiert werden können, doch sobald ich mehr als ein Volume binden möchte, schlägt die Erstellung fehl – ich suche noch nach dem Fehler 😉 Von daher erst einmal die manuelle Einbindung über die DSM-GUI.

Die Files „hosts“ und „resolv.conf“ werden nun zur späteren, korrekten Auflösung(sreihenfolge) des Pi-hole wie hier gezeigt angelegt.

resolv.conf:

nameserver 127.0.0.1
nameserver 1.1.1.1
nameserver 1.0.0.1

hosts:

127.0.0.1  con-pihole
192.168.1.1 <Hostname des VLAN-Gateways>
192.168.1.202 con-pihole

Das Verzeichnis „etc_pihole“ bleibt leer. Darin werden nach dem Start des Servers die gesamten Konfigurationen sowie die entsprechenden Listen gehalten.

Im Verzeichnis „etc_dnsmasq.d“ wird jedoch eine Datei angelegt, um die Namensauflösung im lokalen Netzwerk sauber hinzubekommen – die lokalen Namen sollen ja nicht über externe DNS-Server aufgelöst werden, was diese im Zweifel noch nicht einmal könnten 😉

02-custom.conf:

server=/setup/192.168.1.1
server=/setup.ubnt.com/192.168.1.1
server=/unifi/192.168.1.1
server=/USG/192.168.1.1

server=/localnet/192.168.1.1
server=/home.localnet/192.168.2.1

server=/1.168.192.in-addr.arpa/192.168.1.1
server=/2.168.192.in-addr.arpa/192.168.1.1

Entsprechend, bei weiteren VLANs im lokalen Netzwerk, die Vorwärts- als auch Rückwärts-Auflösung mit in die Liste der 02-custom.conf aufnehmen – ein Eintrag pro Zeile. Das ist natürlich nur nötig, falls pro VLAN ein dediziertes Gateway respektive ein dedizierter DHCP-Host existiert.

Die ersten vier Zeilen dieser Datei sind eine Besonderheit in meinem Netzwerk und nur dann nötig, wenn Netzwerk-Equipment aus dem Hause Ubiquiti zum Einsatz kommt. Sollte das nicht der Fall sein, können eben diese vier Zeilen einfach entfallen.

Da nun das Netzwerk steht, das Routing eingerichtet und der Container konfiguriert ist, kann dieser gestartet werden. In der DSM-GUI sollte das dann im Endergebnis in etwa so aussehen:

Für alle Clients im lokalen Netzwerk muss nun natürlich noch der Pi-hole als DNS-Server bekannt gemacht werden. Ich für meinen Teil habe dies auf meinem DHCP-Server realisiert, in dem ich einfach für die entsprechende DHCP-Option meinen Pi-hole ( hier in meinem Lab: 192.168.1.202 ) eingetragen habe.

Zur Anmeldung an der Web-GUI des Pi-hole nun im Browser die Admin-URL aufrufen

http://192.168.1.202/admin

und nach erfolgter Anmeldung – das Passwort aus der env.txt nicht vergessen – präsentiert sich eine funktionierende Pi-hole-Installation 🙂

Zum Abschluss noch auf der Firewall den gesamten ausgehenden Traffic auf die beiden relevanten DNS-Ports ( 53 und 853, jeweils TCP und UDP ) und den Pi-hole-Server begrenzen und dann war es das auch schon.

Die jetzt folgenden Listenkonfiguration, Performance-Optimierung, Black- und Whitelistings etc. nehme ich nicht in diesen Beitrag mit auf, denn das würde jeden Rahmen sprengen. Der Pi-hole läuft mit einer bereits inkludierten Minimal-Listenkonfiguration und somit viel Spass beim ersten Fernhalten von Spam- und Trackinggedöns – ich werde sicher noch einen weiteren Beitrag nur zu diesem Thema schreiben 🙂

DNS, Internet, Linux, Security


Sven Neidahl

Hallo, ich bin Sven, technikfanatischer Mensch mit Blog-Ambitionen. Ich liebe leckeres Essen, laute Musik und Wandern mit anschliessendem Wellness-Programm, hauptsache "Lebe das Leben mit Liebe, Spass und Technik". Du kannst mich auch auf Facebook und Instagram finden.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.


© 2005 - 2020 - blog.neidahl.de, entstanden mit freundlicher Unterstützung durch Kaffee und meine geliebte Frau