Ein eigener DNS-Server bietet volle Kontrolle über die DNS-Einträge Ihrer Domains. BIND und PowerDNS sind die beiden populärsten Lösungen.

BIND vs PowerDNS

Vergleich

| Merkmal | BIND | PowerDNS | |---------|------|----------| | Verbreitung | Standard seit 1980er | Modern | | Konfiguration | Zone-Dateien | Zone-Dateien oder DB | | Backend | Dateisystem | MySQL, PostgreSQL, etc. | | API | Nein | Ja | | Performance | Gut | Sehr gut | | Clustering | Manuell | Integriert |

BIND Installation

Debian/Ubuntu

apt install bind9 bind9-utils bind9-dnsutils
systemctl enable named
systemctl start named

CentOS/RHEL

dnf install bind bind-utils
systemctl enable named
systemctl start named

Verzeichnisstruktur

/etc/bind/
├── named.conf
├── named.conf.options
├── named.conf.local
├── named.conf.default-zones
├── db.local
├── db.127
└── zones/
    ├── db.example.de
    └── db.192.168.1

BIND Konfiguration

named.conf.options

// /etc/bind/named.conf.options

options {
    directory "/var/cache/bind";

    // Rekursion deaktivieren (nur autoritativ)
    recursion no;
    allow-recursion { none; };

    // Oder Rekursion erlauben (interner Resolver)
    // recursion yes;
    // allow-recursion { 192.168.1.0/24; localhost; };

    // Transfer beschränken
    allow-transfer { none; };

    // DNSSEC
    dnssec-validation auto;

    // IPv4 und IPv6
    listen-on { any; };
    listen-on-v6 { any; };

    // Versionsnummer verstecken
    version "not disclosed";
};

named.conf.local

// /etc/bind/named.conf.local

// Forward Zone
zone "example.de" {
    type master;
    file "/etc/bind/zones/db.example.de";
    allow-transfer { 192.168.1.2; };  // Slave-Server
    also-notify { 192.168.1.2; };
};

// Reverse Zone
zone "1.168.192.in-addr.arpa" {
    type master;
    file "/etc/bind/zones/db.192.168.1";
    allow-transfer { 192.168.1.2; };
};

Forward Zone-Datei

; /etc/bind/zones/db.example.de

$TTL    86400
@       IN      SOA     ns1.example.de. admin.example.de. (
                        2026012601      ; Serial
                        3600            ; Refresh (1 hour)
                        1800            ; Retry (30 min)
                        604800          ; Expire (1 week)
                        86400 )         ; Minimum TTL (1 day)

; Nameserver
@       IN      NS      ns1.example.de.
@       IN      NS      ns2.example.de.

; A-Records
@       IN      A       192.168.1.10
ns1     IN      A       192.168.1.1
ns2     IN      A       192.168.1.2
www     IN      A       192.168.1.10
mail    IN      A       192.168.1.20
ftp     IN      A       192.168.1.30

; AAAA-Records
@       IN      AAAA    2001:db8::10
www     IN      AAAA    2001:db8::10

; CNAME
blog    IN      CNAME   www

; MX-Records
@       IN      MX      10 mail.example.de.
@       IN      MX      20 mail2.example.de.

; TXT-Records
@       IN      TXT     "v=spf1 mx -all"

Reverse Zone-Datei

; /etc/bind/zones/db.192.168.1

$TTL    86400
@       IN      SOA     ns1.example.de. admin.example.de. (
                        2026012601      ; Serial
                        3600            ; Refresh
                        1800            ; Retry
                        604800          ; Expire
                        86400 )         ; Minimum TTL

        IN      NS      ns1.example.de.
        IN      NS      ns2.example.de.

1       IN      PTR     ns1.example.de.
2       IN      PTR     ns2.example.de.
10      IN      PTR     www.example.de.
20      IN      PTR     mail.example.de.

Konfiguration prüfen

# Syntax prüfen
named-checkconf

# Zone prüfen
named-checkzone example.de /etc/bind/zones/db.example.de

# Reload
rndc reload
# oder
systemctl reload named

BIND Slave-Server

Slave-Konfiguration

// /etc/bind/named.conf.local (auf Slave)

zone "example.de" {
    type slave;
    file "/var/cache/bind/db.example.de";
    masters { 192.168.1.1; };  // Master-IP
};

zone "1.168.192.in-addr.arpa" {
    type slave;
    file "/var/cache/bind/db.192.168.1";
    masters { 192.168.1.1; };
};

Transfer testen

# Zone Transfer manuell
dig @192.168.1.1 example.de AXFR

# Status prüfen
rndc zonestatus example.de

PowerDNS Installation

Debian/Ubuntu

apt install pdns-server pdns-backend-mysql
# oder
apt install pdns-server pdns-backend-pgsql

MariaDB-Backend einrichten

# Datenbank erstellen
mysql -u root -p

CREATE DATABASE powerdns;
CREATE USER 'powerdns'@'localhost' IDENTIFIED BY 'password';
GRANT ALL ON powerdns.* TO 'powerdns'@'localhost';
FLUSH PRIVILEGES;

Schema importieren

mysql -u root -p powerdns < /usr/share/doc/pdns-backend-mysql/schema.mysql.sql

PowerDNS konfigurieren

# /etc/powerdns/pdns.conf

# Generell
setuid=pdns
setgid=pdns
local-address=0.0.0.0
local-port=53

# MySQL-Backend
launch=gmysql
gmysql-host=127.0.0.1
gmysql-user=powerdns
gmysql-password=password
gmysql-dbname=powerdns
gmysql-dnssec=yes

# API (optional)
api=yes
api-key=geheimer-api-key
webserver=yes
webserver-address=127.0.0.1
webserver-port=8081

Service starten

systemctl enable pdns
systemctl start pdns

PowerDNS Zonen verwalten

Mit pdnsutil

# Zone erstellen
pdnsutil create-zone example.de ns1.example.de

# Records hinzufügen
pdnsutil add-record example.de @ A 192.168.1.10
pdnsutil add-record example.de www A 192.168.1.10
pdnsutil add-record example.de @ MX "10 mail.example.de"
pdnsutil add-record example.de mail A 192.168.1.20

# Records anzeigen
pdnsutil list-zone example.de

# SOA bearbeiten
pdnsutil set-meta example.de SOA-EDIT-API DEFAULT
pdnsutil increase-serial example.de

Mit SQL

-- Zone einfügen
INSERT INTO domains (name, type) VALUES ('example.de', 'NATIVE');

-- Records einfügen
INSERT INTO records (domain_id, name, type, content, ttl)
VALUES
    (1, 'example.de', 'SOA', 'ns1.example.de admin.example.de 2026012601 10800 3600 604800 3600', 86400),
    (1, 'example.de', 'NS', 'ns1.example.de', 86400),
    (1, 'example.de', 'A', '192.168.1.10', 3600),
    (1, 'www.example.de', 'A', '192.168.1.10', 3600);

Mit API

# Zone erstellen
curl -X POST http://127.0.0.1:8081/api/v1/servers/localhost/zones \
    -H "X-API-Key: geheimer-api-key" \
    -H "Content-Type: application/json" \
    -d '{
        "name": "example.de.",
        "kind": "Native",
        "nameservers": ["ns1.example.de.", "ns2.example.de."]
    }'

# Record hinzufügen
curl -X PATCH http://127.0.0.1:8081/api/v1/servers/localhost/zones/example.de. \
    -H "X-API-Key: geheimer-api-key" \
    -H "Content-Type: application/json" \
    -d '{
        "rrsets": [{
            "name": "www.example.de.",
            "type": "A",
            "ttl": 3600,
            "changetype": "REPLACE",
            "records": [{"content": "192.168.1.10", "disabled": false}]
        }]
    }'

PowerDNS Replikation

Mit MySQL-Replikation

Master (MySQL) ←→ Slave (MySQL)
      ↓                ↓
   PowerDNS         PowerDNS

Native PowerDNS Replikation

# Master (pdns.conf)
master=yes
slave=no

# Slave (pdns.conf)
master=no
slave=yes
slave-cycle-interval=60
# Slave-Zone einrichten
pdnsutil create-slave-zone example.de 192.168.1.1

Firewall

UFW

ufw allow 53/tcp
ufw allow 53/udp

iptables

iptables -A INPUT -p tcp --dport 53 -j ACCEPT
iptables -A INPUT -p udp --dport 53 -j ACCEPT

Testen

DNS-Abfragen

# Lokal testen
dig @localhost example.de
dig @localhost www.example.de A
dig @localhost example.de MX
dig @localhost example.de NS

# Reverse Lookup
dig @localhost -x 192.168.1.10

# Zone Transfer (wenn erlaubt)
dig @localhost example.de AXFR

Von extern

# Von anderem Server
dig @192.168.1.1 example.de

# Nach Registrar-Eintrag
dig example.de +trace

Monitoring

BIND-Statistiken

# Statistiken aktivieren
# /etc/bind/named.conf.options
statistics-channels {
    inet 127.0.0.1 port 8053 allow { 127.0.0.1; };
};

# Abfragen
curl http://127.0.0.1:8053/
rndc stats

PowerDNS-Statistiken

# Über API
curl http://127.0.0.1:8081/api/v1/servers/localhost/statistics \
    -H "X-API-Key: geheimer-api-key"

# Oder
pdns_control show '*'

Troubleshooting

BIND-Logs

# Journal
journalctl -u named -f

# Query Log aktivieren
rndc querylog on

# Tail
tail -f /var/log/syslog | grep named

PowerDNS-Logs

journalctl -u pdns -f

Häufige Probleme

# Port 53 bereits belegt?
ss -tulpn | grep :53

# systemd-resolved deaktivieren
systemctl stop systemd-resolved
systemctl disable systemd-resolved
rm /etc/resolv.conf
echo "nameserver 8.8.8.8" > /etc/resolv.conf

# Berechtigungen
chown -R bind:bind /etc/bind/zones

Zusammenfassung

| Funktion | BIND | PowerDNS | |----------|------|----------| | Config prüfen | named-checkconf | pdnsutil check-zone | | Zone erstellen | Datei anlegen | pdnsutil create-zone | | Reload | rndc reload | pdns_control reload | | Stats | rndc stats | pdns_control show '*' |

| Record-Typ | Bedeutung | |------------|-----------| | A | IPv4-Adresse | | AAAA | IPv6-Adresse | | NS | Nameserver | | MX | Mailserver | | CNAME | Alias | | TXT | Text (SPF, DKIM) | | SOA | Zone-Info | | PTR | Reverse DNS |

| Datei | Funktion | |-------|----------| | named.conf | Hauptkonfiguration | | named.conf.options | Globale Optionen | | named.conf.local | Zonen-Definition | | db.example.de | Zone-Datei |

Fazit

Ein eigener DNS-Server bietet maximale Kontrolle und Flexibilität. BIND ist der klassische Standard mit bewährter Stabilität. PowerDNS punktet mit API und Datenbank-Backend. Für hohe Verfügbarkeit sind mindestens zwei DNS-Server erforderlich. Die Konfiguration erfordert Sorgfalt, da DNS-Fehler weitreichende Auswirkungen haben.