Teil der Story Mein Netzwerk

Eigene Nameserver & Resolver – Mein Setup

PowerDNS Authoritative, PowerDNS Recursor & dnsdist self-hosted

Auch die DNS-Infrastruktur für mein Netzwerk betreibe ich selbst. Das heißt, sowohl die Nameserver für die öffentlichen und privaten Domains, als auch die Resolver, die alle meine Geräte ausschließlich benutzen. Wobei diese Resolver auch öffentlich erreichbar sind, weil warum nicht. Hier möchte ich das Setup mal kurz vorstellen.

Motiviation

Wie immer – Lerneffekt, #ownyourdata und zeigen, dass das Internet ein dezentraler Ort ist. Datenschutz ist nämlich auch und vor allem bei DNS-Anfragen wichtig.

Übersicht

Es gibt 3 Server:

  • ns-grandmajor.berrnd.net ist primärer autoritativer Server für die eigenen Domains, kein Resolver
  • ns-major.berrnd.net ist sekundärer autoritativer Server für die eigenen Domains  sowie öffentlicher Resolver
  • ns-minor.berrnd.net ist tertiärer autoritativer Server für die eigenen Domains sowie ebenfalls öffentlicher Resolver

Alle Server sind dabei LXC Container unter Proxmox, die jeweils einen CPU-Kern und 256 MB RAM zugeordnet haben.

Verwendete Software

Ich verwende für mein Setup das komplette Programm von PowerDNS:

  • PowerDNS Authoritative für die eigenen Domains
  • PowerDNS Recursor für den Resolver-Job
  • dnsdist als „Frontend“, nur dnsdist ist von außen erreichbar und verteilt entsprechend ob die Anfrage eine eigene Domain betrifft, oder nicht
  • Eine angepasste Version, erweitert um z. B. Dynamic DNS Support, von nsedit zur Verwaltung über eine komfortable Weboberfläche

nsedit Weboberfläche auf "ns-major.berrnd.net"

Die Konfiguration

Die Konfigurationen sind auf allen 3 Servern komplett gleich, bis auf den Unterschied Master-/Slave Betrieb und dass einer kein Resolver ist, die folgenden Konfigurationen beziehen sich auf ns-major.berrnd.net.

PowerDNS Authoritative läuft auf Port 1053 und ist nur von lokal erreichbar. Die wichtigsten von mir angepassten Einstellungen sind nachfolgend aufgeführt.

allow-axfr-ips=127.0.0.0/8,::1
any-to-tcp=yes
api=yes
api-key=xxxx
daemon=yes
launch=gsqlite3
gsqlite3-database=/etc/powerdns/pdns.db
gsqlite3-dnssec=on
gsqlite3-pragma-synchronous=0
local-address=127.0.0.1
local-port=1053
master=yes
setgid=pdns
setuid=pdns
trusted-notification-proxy=127.0.0.1

PowerDNS Recursor läuft auf Port 2053 und ist ebenfalls nur von lokal erreichbar. Auch hier habe ich nur die nötigen Einstellungen wie folgt angepasst.

allow-from=127.0.0.0/8,::1/128
any-to-tcp=yes
api-key=xxxx
api-readonly=yes
daemon=yes
local-address=127.0.0.1
local-port=2053
lowercase-outgoing=yes
setgid=pdns
setuid=pdns

dnsdist läuft auf dem DNS-Standardport 53 und ist selbstverständlich öffentlich erreichbar. Dieser Dienst verteilt die Anfragen an die beiden anderen Dienste, die Konfigurationsdatei sieht bei mir wie folgt aus.

setLocal("0.0.0.0:53")
setACL({"0.0.0.0/0"})

newServer({address="127.0.0.1:1053", pool="authoritative"})
newServer({address="127.0.0.1:2053", pool="recursor"})

webserver("0.0.0.0:8103", "xxxx")

-- Block hosts that exceeded 100 queries in 10 seconds for 30 minutes
function maintenance()
	addDynBlocks(exceedQRate(100, 10), "Exceeded query rate", 1800)
end

-- Allow AXFR to ns-minor.berrnd.net and ns-grandmajor.berrnd.net
addAction(AndRule({OrRule({QTypeRule(dnsdist.AXFR), QTypeRule(dnsdist.IXFR)}), NotRule(makeRule({"ipv4.of.ns-minor.xx/32", "ipv4.of.ns-grandmajor.xx/32"}))}), RCodeAction(dnsdist.REFUSED))

-- Allow NOTIFY from ns-minor.berrnd.net and ns-grandmajor.berrnd.net
addAction(AndRule({OpcodeRule(DNSOpcode.Notify), NotRule(makeRule({"ipv4.of.ns-minor.xx/32", "ipv4.of.ns-grandmajor.xx/32"}))}), RCodeAction(dnsdist.REFUSED))

addAction("berrnd.de.", PoolAction("authoritative"))
addAction("berrnd.org.", PoolAction("authoritative"))
addAction("berrnd.net.", PoolAction("authoritative"))
-- ... other domains ...
addAction(AllRule(), PoolAction("recursor"))

dnsdist Weboberfläche auf "ns-major.berrnd.net"Auf die Konfiguration von nsedit und einem entsprechenden Webserver gehe ich hier nicht konkreter ein, das ist nicht mehr wie bei jeder gewöhnlichen PHP Webanwendung.

Fazit

Bei mir läuft dieses Setup schon seit einigen Jahren (nicht in konkret dieser Form schon seit Anfang) absolut stabil und performant.

Und wer meine Resolver verwenden will, warum auch immer – gerne doch – für weitere Informationen einfach die o. g. Servername im Browser aufrufen. Wie für die meisten meiner Dienste, gibt es auch für DNS-Server kleine Infoseiten – siehe z. B. https://ns-major.berrnd.net.

Schreibe einen Kommentar

Kommentar

  1. Hi Bernd, könntest du hier vielleicht doch noch einmal auf deine Config von NSEdit eingehen. Ich versuche seit Tagen dieses zum laufen zu bekommen. Kurz zu meinem Aufbau:
    Ich habe auf einem Server PDNS, PDNS-Resolver und DNSDist installiert. Unter der URL: http://server:8083 kann ich auch die Website von PDNS aufrufen und DNS Auflösungen gehen auch. Auf einem seperaten Server habe ich dann NGINX mit SQLite3 und PHP-FPM installiert. NGINX Seite geht, eine PHP Testseite geht auch. Wenn ich dann NSEdit von deinem Git Repository herunterlade und die /includes/config.inc.php anpasse bekomme ich ein leere Seite angezeigt. NGINX habe ich natürlich auch noch entsprechend für PHP angepasst.
    Vielen Dank.
    Gruß
    Johannes

    • Hallo Johannes,

      bei mir läuft nsedit direkt auf demselben Server, wo auch PDNS, etc. läuft, aber das sollte ja keinen Unterschied machen. Wenn einfach eine leere Seite kommt, vermute ich eher ein PHP Problem generell – müsste ja aber entweder im NGINX oder PHP Log was dazu auftauchen…

      Der obere Teil meiner config.inc.php für nsedit:
      $apipass = 'JfFCkudy45UOI8M56OBTJCbqb'; # The PowerDNS API-key
      $apiip = '127.0.0.1'; # The IP of the PowerDNS API
      $apiport = '8101'; # The port of the PowerDNS API
      $apiproto = 'http'; # http | https
      $apisslverify = FALSE; # Verify SSL Certificate if using https for apiproto
      $allowzoneadd = FALSE; # Allow normal users to add zones
      $logging = TRUE;

      Ich benutze aktuell PHP 7.2, der location block in der NGINX config sieht dann so aus:
      location /nsedit {
      alias /var/www/nsedit;

      location ~* \.(php|inc)$ {
      include fastcgi.conf;

      fastcgi_pass unix:/run/php/php7.2-fpm.sock;
      fastcgi_index index.php;
      fastcgi_intercept_errors on;
      fastcgi_buffer_size 16k;
      fastcgi_buffers 4 16k;
      }
      }

      Grüße,
      Bernd

      • Hi Bernd,
        okay ich hab jetzt mal schnell meine NGINX Config angepasst:

        server {
        listen 80 default_server;
        listen [::]:80 default_server;
        root /var/www/nsedit/;

        index index.php index.html index.htm;

        server_name _;

        location /nsedit {
        alias /var/www/nsedit;

        location ~* \.(php|inc)$ {
        include fastcgi.conf;

        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
        fastcgi_index index.php;
        fastcgi_intercept_errors on;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
        }
        }
        }
        NSEdit liegt in /var/www/nsedit/.

        Jetzt bekomme ich einen Download angeboten.

        Gruß

        Johannes

        • Hatte ich auch schon mal, war was in der Richtung: https://stackoverflow.com/a/28644277

          Hier vll. mal noch die fastcgi.conf vergleichen (meine müsste aber der NGINX Default sein):
          fastcgi_param SCRIPT_FILENAME $request_filename;
          fastcgi_param PATH_INFO $fastcgi_script_name;
          fastcgi_param QUERY_STRING $query_string;
          fastcgi_param REQUEST_METHOD $request_method;
          fastcgi_param CONTENT_TYPE $content_type;
          fastcgi_param CONTENT_LENGTH $content_length;

          fastcgi_param SCRIPT_NAME $fastcgi_script_name;
          fastcgi_param REQUEST_URI $request_uri;
          fastcgi_param DOCUMENT_URI $document_uri;
          fastcgi_param DOCUMENT_ROOT $document_root;
          fastcgi_param SERVER_PROTOCOL $server_protocol;
          fastcgi_param HTTPS $https if_not_empty;

          fastcgi_param GATEWAY_INTERFACE CGI/1.1;
          fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;

          fastcgi_param REMOTE_ADDR $remote_addr;
          fastcgi_param REMOTE_PORT $remote_port;
          fastcgi_param SERVER_ADDR $server_addr;
          fastcgi_param SERVER_PORT $server_port;
          fastcgi_param SERVER_NAME $server_name;