Pi-Hole – DNS über HTTPS (DoH) mit nignx

Hier ist einmal Version 1 meiner Anleitung, um die DNS-Abfragen zum Pi-Hole via HTTPS zu verschlüsseln.
Ich habe schon einmal eine Anleitung für DNS-over-TLS gemacht.
Diese Anleitung knüpft an diese an, kann aber auch komplett getrennt genutzt werden.
Diese Anleitung ist dann Sinnvoll, wenn dein DNS-Server im Internet erreichbar ist.
DoH in diesem Aufbau für Zuhause ist nicht gut, da die DNS-Abfragen ab dem Pi-Hole wieder unverschlüsselt durchs Netz wandern!

Mit DoH lassen sich all unsere DNS-Abfragen über den Port 443 schicken und gleichzeitig mit SSL verschlüsseln.

WARNUNG: Das hier ist aktuell Version 1! Es gibt ggf. noch Verbesserungsbedarf.
Es ist aktuell eine „kopiere alles ab und erfreue dich“-Anleitung. Ich erkläre nur die notwendigen Änderungen, gehe aber nicht tiefer darauf ein.

Los gehts!

Vorraussetzung:
Eine laufende Pi-Hole-Installation
nginx als Webserver
– Eine Domain die auf den Server aufgeschaltet ist
– Etwas freier Speicher auf dem Server
– Root-Rechte

Schritt 1: Installieren von Golang

Wir brauchen Golang, damit wir die neuste Version de DoH-Server erstellen können.
Ist GO bei dir schon installiert, kannst du den Schritt überspringen.
Zuerst besorgen wir uns GO.

# wget https://dl.google.com/go/go1.13.8.linux-amd64.tar.gz
# tar xvfz go1.13.8.linux-amd64.tar.gz
# mv go /usr/local/go

Wir fügen Go in unsere Umgebungsvariablen hinzu:
(Alles abkopieren und als eine Befehlszeile abschicken!)

# cat << 'EOF' >> ~/.bashrc
export GOROOT=/usr/local/go
export GOPATH=$HOME/goProjects
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH

Nun noch 3 Befehle und wir sind fertig:

# mkdir ~/goProjects
# source ~/.bashrc
# go version

Schritt 2: DoH installieren

Nun installieren wir unseren DNS over HTTPS Server.

# apt install curl software-properties-common build-essential -y
# wget https://github.com/m13253/dns-over-https/archive/v2.2.1.zip
# unzip v2.2.1.zip
# cd dns-over-https-2.2.1/
# make
# make install

Wir müssen nun die Config noch Anpassen.

# nano /etc/dns-over-https/doh-server.conf

Editiere hier die Upstream-Server auf deine Wünsche. Hast du nur ein Pi-Hole, trage z.B. nur die Localhost-Adresse ein.

upstream = [
    "udp:127.0.0.1:53",
]

Nun lässt sich unser DoH-Server auch schon starten!

# systemctl restart doh-server

Schritt 3: Lets Encryp installieren und ein Zertifikat ausstellen

Wir brauchen ein gültiges Zertifikat, damit wir sichere Abfragen ohne Hindernis machen können.

# apt install certbot -y
# certbot certonly -d deine.domain.de

Schritt 4: Die nginx-Config

Hier ist eine Beispiel-Config für nginx.
Sie muss nun von dir noch etwas angepasst werden. Die FETT markierten Stellen, müssen auf jeden Fall angepasst werden.
Was muss angepasst werden?
server_name → Deine genutzte Domain eintragen
ssl_certificate + ssl_certificate_key → Pfad zu deinem Zertifikat anpassen
access_log + error_log → Pfad anpassen

# apt install nginx
# nano /etc/nginx/sites-enabled/doh

Hier die Beispiel-Config:

upstream dns-backend {
    server 127.0.0.1:8053;
    keepalive 30;
}
server {
    listen 80;
    listen [::]:80;

    location /.well-known/acme-challenge {
        alias /var/www/dehydrated;
    }
    root /var/www/html;

    server_name deine.domain.de;
    return 301 https://$host;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    location /.well-known/acme-challenge {
      alias /var/www/dehydrated;
    }
    ssl_certificate /etc/letsencrypt/live/deine.domain.de/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/deine.domain.de/privkey.pem;

    # enables all versions of TLS, but not SSLv2 or 3 which are weak and now deprecated.
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    # disables all weak ciphers
    ssl_ciphers 'AES128+EECDH:AES128+EDH';

    ssl_prefer_server_ciphers on;

    root /var/www/html;

    index index.html index.htm index.nginx-debian.html;

    server_name deine.domain.de;
    access_log /var/log/nginx/deine.domain.de-access.log;
    error_log /var/log/nginx/deine.domain.de-error.log;

    location /dns-query {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_set_header Connection "";
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_redirect off;
        proxy_set_header        X-Forwarded-Proto $scheme;
        proxy_read_timeout 86400;
        proxy_pass http://dns-backend/dns-query;
    }

}

Nun noch kurz nginx testen und dann neu starten:

# nginx -t
# service nginx restart

Tipp: Wenn du das Webinterface von Internet aus erreichen möchtest, setzte eine weitre Passwortabfrage via nginx davor (zwecks Bruteforce-Schutz) und nutze ein anderen Port (z.B. 8443).
Ich würde den Admin-Bereich zur Sicherheit nicht auf die gleiche Adresse / Port legen, unter dem auch der DoH-Server erreichbar ist.

Damit sind wir fertig!
Nun kannst du mit z.B. dem Firefox testen, ob DNS-Abfragen über HTTPS möglich sind.
Wir können die Funktion auch so testen, indem wir direkt den Server mit einer Aufgabe ansteuern.
Rufe dazu einfach folgende URL auf:

https://dein-pihole.de/dns-query?name=hoerli.net&amp;type=A

Du solltest ein Ausgabe im JSON-Format erhalten.

Viel Spaß mit DoH und Pi-Hole!


Denke auch daran GO und DoH von Zeit zur Zeit zu aktualisieren.
Einfach die Pakete neu herunterladen, den GO-Ordner einfach entfernen und gegen das neue Archiv ersetzen.
DoH kann dann einfach “neu” installiert werden. Einfach drüber bügeln und den Dienst neu starten lassen.

3 Kommentare

  1. Servus,
    Ich bekomme leider beim testen, also im letzten Schritt die Fehlermeldung: SSL received a record that exceeded the maximum permissible length. (Error code: ssl_error_rx_record_too_long). Ich benutze für DoH dasselbe Zertifikat wie für DoT und DoT funktioniert ohne Probleme. Kann mir da evtl. Jemand helfen?

    • Hi!
      Vielleicht ist bei der Zertifikatsausstellen was schief gelaufen oder die Konfiguration ist falsch.
      ssl_error_rx_record_too_long deutet meist auf ein ungültiges (ggf. zum Hostname) Zertifikat hin.

  2. Hallo,
    erstmal Danke für deine viele Mühe. Sehr interessant mal wieder. Ich finde den hier beschriebenen Ansatz für DOH mit Nginx und Pihole allerdings deutlich einfacher:
    https://blog.casakampa.nl/dns-over-https-with-nginx-dnsdist-and-pi-hole/

Schreibe einen Kommentar

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

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.