Mein eigenes DynDNS
Eigentlich nerven mich die bisherigen DynDNS-Dienst schon lange. Die Namensauflösung funktionierte bei mir nicht mehr zuverlässig und ständig muss man den Service erneut aktivieren. Von daher lag es schon immer nah selber einen entsprechenden Dienst auf dem eigenen Root-Server aufzusetzen. Es erschien mir aber immer zu aufwändig, ich hätte mir dazu mehr über Bind anlesen müssen.
Da war der Artikel ab Seite 196 in der c't 24/2013 ein Clou. Schon beim ersten Überfliegen war mir klar, dass es genau um mein Problem ging. Irgendwann wurde mir dann auch der Trick klar. Hier wird nicht Bind als Nameserver benutzt, sondern PowerDNS. Dieser Nameserver speichert seine Daten in einer SQL-Datenbank, was die Manipulation der Records über ein eigenes PHP-Script wesentlich erleichtert.
In dem Artikel benutzt der Autor die Datenbank sqlite3, auf meinem Server läuft aber sowieso MySQL und da lassen sich die Einträge mit phpMyAmin gleich schön verwalten. Ich habe also unter openSUSE folgende Pakte
- pdns-backend-mysql
- pdns
nachinstalliert.
Per Hand nachinstallieren musste ich die Verwaltungsoberfläche Poweradmin, die man von http://www.poweradmin.org/ beziehen kann. Ich muss mir bei nächster Gelegenheit auch den PDNS Manager https://pdnsmanager.lmitsystems.de/ bzw. https://github.com/loewexy/pdnsmanager einmal ansehen.
MySQL-Datenbank
Mittels phpMyAdmin habe ich mir dann eine MySQL-Datenbank angelegt mit folgenden Tabellen:
create table domains ( id NUMBER, name VARCHAR(255) NOT NULL, master VARCHAR(128) DEFAULT NULL, last_check INT DEFAULT NULL, type VARCHAR(6) NOT NULL, notified_serial INT DEFAULT NULL, account VARCHAR(40) DEFAULT NULL, primary key (id) ); create sequence DOMAINS_ID_SEQUENCE; create index DOMAINS$NAME on Domains (NAME); CREATE TABLE records ( id number(11) not NULL, domain_id INT DEFAULT NULL REFERENCES Domains(ID) ON DELETE CASCADE, name VARCHAR(255) DEFAULT NULL, type VARCHAR(6) DEFAULT NULL, content VARCHAR(255) DEFAULT NULL, ttl INT DEFAULT NULL, prio INT DEFAULT NULL, change_date INT DEFAULT NULL, primary key (id) ); create index RECORDS$NAME on RECORDS (NAME); create sequence RECORDS_ID_SEQUENCE; create table supermasters ( ip VARCHAR(25) NOT NULL, nameserver VARCHAR(255) NOT NULL, account VARCHAR(40) DEFAULT NULL );
PowerDNS-Konfiguration
In der Datei /etc/pdns/pdns.conf habe ich dann folgende Einstellungen vorgenommen:
allow-axfr-ips=85.214.36.141 127.0.0.1 173.244.206.26 88.198.106.11 allow-recursion=127.0.0.1 master=yes disable-axfr=no launch=gmysql gmysql-dbname=<datenbank> gmysql-host=127.0.0.1 gmysql-password=<db-passwort> gmysql-user=<db-benutzername>
In dem ersten Teil wird eingestellt, dass es sich um den Master-Server für die zu konfigurierende Domain handelt und dass Zonentransfers für bestimmte Rechner erlaubt sind. Die ersten beiden IPs beziehen sich auf den Rechner selber (meinen Rechner), die beiden hinteren IPs auf die Zonen-Transfer Server von http://BuddyNS.com.
Im zweiten Teil sind dann die Zugangsdaten für die Datenbank zu finden.
Secondary Nameserver
Mit PowerDNS kann man auch einen Secondary-Nameserver einrichten, der sich selbstständig mit seinem Master synchronisiert.
Wenn man für eine eigene Domain die Namensauflösung selber verwalten möchte, so benötigt man zwei Nameserver, die sich nicht im gleichen Netzwerksegment befinden dürfen. Meine Server sind alles Strato-Server und erfüllen diese Bedingung nicht ohne weitere Tricks. Da trifft es sich gut, dass in dem Artikel auch http://BuddyNS.com vorgestellt wird, ein Dienst, der den notwendigen Service kostenlos anbietet.
Die Einrichtung von BuddyNS ist ganz einfach und sollte aber erst erfolgen, wenn der eigenen Nameserver entsprechend funktioniert. Der BuddyNS erfragt nur notwendige Daten, die unter http://www.buddyns.com/activation/ angegeben werden.
Es sind dies nur der Name der Domain, die IP-Adresse des ersten Nameservers und eine Mailadresse. An diese Mailadresse bekommt man dann seine Zugangsdaten geschickt. Benutzername ist die angegebene Mailadresse, dazu kommt dann eine kryptische Zeichenkette als Passwort. Mit diesen Daten kann man sich dann unter https://www.buddyns.com/buddyboard/ anmelden und die Einstellungen überprüfen.
Wichtig ist hier der Link auf die Seite Zones:
Hier kann man sehen, ob die Einstellungen in Ordnung sind und BuddyNS die angegebene Zonendatei laden kann. In zwei Zeilen wird es am Anfang eine Fehlermeldung geben und zwar bei:
- Authority declares BuddyNS
- Registry declares BuddyNS
Hier müssen erst die Einträge beim Registrar der Domain erfolgt sein.
Das Mühlenrad rechts neben dem grünen Balken (bis alles stimmt ist der übrigens rot) dient dazu einen sofortigen Zonentransfer auszulösen. Der automatische Zonentransfer erfolgt aber immer sehr schnell, nachdem am Primary Nameserver die Seriennummer erhöht wurde.
Sehr hilfreich finde ich auch, dass hier sehr genau angezeigt wird, wann der letzte Transfer erfolgt ist und die zugehörige Seriennummer angezeigt wird (man muss die Seite natürlich neu laden, um Änderungen bemerken zu können).
Ob nun alle Einstellungen in Ordnung sind kann man auf der Seite http://www.intodns.com/ testen lassen.
Mit diesen Informationen kann man die meisten Fehler erkennen und beseitigen.
Eintragen beim Registrar
Wenn alle Konfigurationsschritte erfolgreich abgeschlossen sind, dann kann man unter http://www.denic.de/hintergrund/nast.html testen, ob die Nameserver auch beim DENic akzeptiert werden.
Wenn dieser Test erfolgreich verlaufen ist, dann kann man die Nameserver-Einstellung beim Registrar ändern.Die Einstellungen sind dann aber noch nicht sofort aktiv. Mein Registrar http://df.eu überträgt halbstündlich zum denic. Danach dauert es dann aber noch einige Stunden, bis diese Änderungen überall angekommen sind und das eigene DynDNS funktioniert.
Das Update-Script
Nun braucht man noch ein kleines PHP-Script auf dem Server, welches vom Client-Rechner aufgerufen wird, den Rechnernamen und die aktuelle IP-Adresse bekommt und in die PowerDNS-Datenbank einträgt. Momentan nutze ich noch das PHP-Skript zu dem Artikel und liste es daher hier nicht auf. Ich werde aber in der nächsten Etappe sicherlich eine eigene Erweiterung vornehmen und dann hier veröffentlichen.
Solange nur drei klein Brocken. Der Autor benutzt für die Datenbank-Anbindung die PDO-Funktionen von PHP: http://php.net/manual/de/book.pdo.php .
Der Verbindungsaufbau erfolgt mittels:
$db = new PDO("mysql:host=localhost;dbname=<datenbank>","<db-benutzer>", "<db-password>");
Setzen der IP-Adresse:
$dbh = $db->query("update records set content='$IP' where name='$HOSTNAME'");
Im Feld content befindet sich im SOA-Record eine Reihe von Informationen, unter anderem die Seriennummer, die erhöht werden muss. Daher muss man die Elemente in diesen Feld erst einmal zerlegen. Der folgende Ansatz ist dafür recht elegant:
preg_match("/([^\s]+) ([^\s]+) (\d+) (\d+) (\d+) (\d+) (\d+)/", $row['content'], $match);
Eine Änderung an dem Script muss man wohl für die Fritz!Box vornehmen:
#print("Success."); print("good ".$IP);
Statt Success erwartet die Box als Rückmeldung good gefolgt von der aktuellen IP (Nachtrag: scheint leider auch nicht zu stimmen).
- http://de.dyn.com/support/developers/api/return-codes/
- https://ssl.tiggerswelt.net/wiki/ddns/informationen_fuer_entwickler
Ändert man die Zeile nicht, so funktioniert das Update zwar, die Box zeigt aber trotzdem eine Fehlermeldung.
29.12.13 03:51:29 Dynamic DNS-Fehler: Die Dynamic DNS-Aktualisierung war erfolgreich, anschließend trat jedoch ein Fehler bei der DNS-Auflösung auf.
Konfiguration der Fritz!Box
Nun muss nur noch die Box beim Verbindungsaufbau das Update-Script aktualisieren.
Dazu geht man auf Internet -> Freigaben -> Dynamic DNS. Hier wählt man Benutzerdefiniert als Anbieter und gibt dann die notwendigen Daten an.
Im vorliegenden Beispiel steht in der Zeile Update-URL:
<meine domain>/poweradmin/update.php?hostname=<domain>&kennwort=<pass>
Die Zeile beginnt direkt mit dem Domainnamen, also ohne http:// davor.
Die FritzBox kennt einige Platzhalter (siehe Screenshot) für die Daten in der URL, die sich in der Regel auf die Zeilen darunter beziehen. Man kann die URL natürlich auch ohne Nutzung der Zeilen darunter zusammenstellen.
Ich rufe zusätzlich noch einmal pro Stunde die Aktualisierung per Cron-Job auf:
45 * * * * /usr/bin/wget -O /dev/null "http://<meine Domain>/poweradmin/update.php?hostname=<mein hostname>" > /dev/null 2>&
Nachtrag 2015
Das beschriebene System funktioniert bei mir seit der Einrichtung problemlos. Nach neuen Experimenten mit PowerDNS würde ich heute manche Dinge anders lösen. Spätestens beim nächsten Wechsel des Strato-Servers werde ich das auch sicher umsetzen. Hier schon einmal ein paar Grundlagen für Veränderungen.
MySQL
PowerDNS liefert immer noch keine Datei mit zur Datenbankinstallation, liefert aber eine Reihe von Kommandozeilen. Wenn man die ausführt, dann kommt man zu folgender Datenbank-Datei:
CREATE TABLE `comments` ( `id` int(11) NOT NULL AUTO_INCREMENT, `domain_id` int(11) NOT NULL, `name` varchar(255) NOT NULL, `type` varchar(10) NOT NULL, `modified_at` int(11) NOT NULL, `account` varchar(40) NOT NULL, `comment` varchar(6400) NOT NULL, PRIMARY KEY (`id`), KEY `comments_domain_id_idx` (`domain_id`), KEY `comments_name_type_idx` (`name`,`type`), KEY `comments_order_idx` (`domain_id`,`modified_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `cryptokeys` ( `id` int(11) NOT NULL AUTO_INCREMENT, `domain_id` int(11) NOT NULL, `flags` int(11) NOT NULL, `active` tinyint(1) DEFAULT NULL, `content` text, PRIMARY KEY (`id`), KEY `domainidindex` (`domain_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `domainmetadata` ( `id` int(11) NOT NULL AUTO_INCREMENT, `domain_id` int(11) NOT NULL, `kind` varchar(32) DEFAULT NULL, `content` text, PRIMARY KEY (`id`), KEY `domainmetadata_idx` (`domain_id`,`kind`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `domains` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `master` varchar(128) DEFAULT NULL, `last_check` int(11) DEFAULT NULL, `type` varchar(6) NOT NULL, `notified_serial` int(11) DEFAULT NULL, `account` varchar(40) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `name_index` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `records` ( `id` int(11) NOT NULL AUTO_INCREMENT, `domain_id` int(11) DEFAULT NULL, `name` varchar(255) DEFAULT NULL, `type` varchar(10) DEFAULT NULL, `content` varchar(6400) DEFAULT NULL, `ttl` int(11) DEFAULT NULL, `prio` int(11) DEFAULT NULL, `change_date` int(11) DEFAULT NULL, `disabled` tinyint(1) DEFAULT '0', `ordername` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `auth` tinyint(1) DEFAULT '1', PRIMARY KEY (`id`), KEY `nametype_index` (`name`,`type`), KEY `domain_id` (`domain_id`), KEY `recordorder` (`domain_id`,`ordername`), CONSTRAINT `records_ibfk_1` FOREIGN KEY (`domain_id`) REFERENCES `domains` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `supermasters` ( `ip` varchar(64) NOT NULL, `nameserver` varchar(255) NOT NULL, `account` varchar(40) NOT NULL, PRIMARY KEY (`ip`,`nameserver`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `tsigkeys` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `algorithm` varchar(50) DEFAULT NULL, `secret` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `namealgoindex` (`name`,`algorithm`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Domain
Der c't Artikel und auch meine Beschreibung gehen davon aus, dass man eine komplette Domain als Grundlage benutzt. Viel einfacher ist es aber, nur eine Subdomain zu nutzen. Dann spart man sich den zweiten Nameserver (hier BuddyNS) und auch den ganzen Aufwand mit der Registrierungsstelle.
Bei Domainfactory braucht man dafür eigentlich nur zwei Eintrage bei einer der eigenen Domains:
dyndns.zzz-server.de NS dns.zzz-server.de dns.zzz-server.de A 85.214.xxx.yyy
Der Nameserver-Eintrag muss auf einen cname Verweisen, man darf hier keine IP-Adresse eintragen, obwohl Domainfactory das zulässt.
Dann arbeitet man eben mit der Domain dyndns.zzz-server.de als Grundlage und nicht mit zzz-server.de.
PowerDNS
Die Konfiguration vereinfacht sich dann zu
master=yes launch=gmysql gmysql-dbname=<datenbank> gmysql-host=127.0.0.1 gmysql-password=<db-passwort> gmysql-user=<db-benutzer>
Zusätzlich kann man auch das Logging noch intensivieren:
log-dns-details=yes log-dns-queries=yes loglevel=9
Was ich wirklich blöd finde ist die Situation bei den Webfrontends für PowerDNS.
Der Klassiker ist ja immer noch Poweradmin, das wirkt aber wie aus einer vergangenen Zeit.
Links
- https://github.com/PowerDNS/pdns/wiki/WebFrontends Übersicht über Frontends
- http://www.admin-magazin.de/Das-Heft/2013/12/Nameserver-mit-PowerDNS/
- http://www.pro-linux.de/artikel/2/1652/2,eintrag-in-die-datenbank.html
- http://www.poweradmin.org/
- https://www.howtoforge.com/installing-powerdns-with-mysql-backend-and-poweradmin-on-debian-etch
- https://www.openhub.net/p/pdns-gui
- http://www.powerdns-gui.org/
- http://sourceforge.net/projects/dmsmaster
- http://phpdnsadmin.sourceforge.net/
- http://sourceforge.net/projects/powerdnsadmin/
- http://sourceforge.net/projects/publicdnsadmin
- http://www.tupa-dns.org/
- http://freecode.com/projects/zoneadmin/ bzw http://open.megabit.net/index.php?section=pro_home&project=ZoneAdmin
- https://github.com/averna-syd/PowerdnsTango sieht sehr interessant aus (Perl und viele Module)
- https://pypi.python.org/pypi/django-powerdns-manager (Python-Django, recht aktuell)
mögliche Alternativen:
Ubuntu 16.04
Bei dieser Ubuntu-Version sind eigentlich die Pakete:
- pdns-backend-mysql
- pdns-server
dabei. Dies Version funktioniert aber nicht (siehe auch https://github.com/PowerDNS/pdns/issues/4232).
backend reported condition which prevented lookup (GSQLBackend lookup query: Could not execute mysql statement: SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and type=? and name=?: Lost connection to MySQL server during query) sending out servfail Backend reported condition which prevented lookup (GSQLBackend lookup query: Could not execute mysql statement: SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and type=? and name=?: Lost connection to MySQL server during query) sending out servfail
Erst ein Update auf eine aktuelle Verion (https://repo.powerdns.com/#ubuntuxenialauth-41) hat das Problem gelöst: Datei /etc/apt/sources.list.d/pdns.list erstellen mit:
deb [arch=amd64] http://repo.powerdns.com/ubuntu xenial-auth-41 main
Datei /etc/apt/preferences.d/pdns erstellen mit:
Package: pdns-* Pin: origin repo.powerdns.com Pin-Priority: 600
curl https://repo.powerdns.com/FD380FBB-pub.asc | sudo apt-key add - apt-get update apt-get install pdns-server pdns-backend-mysql
Als Frontende habe ich den PDNS Manager gewählt. Die Einrichtung ist recht einfach, einfach in ein vom Webserver erreichbares Verzeichnis entpacken (z.B. /pdnsm) und dort die URL http://<webserver>/pdnsm/install.php aufrufen. Es werden dann die Datenbank-Einstellungen für pdns erfagt und die Daten für das Anlegen eines Accounts zur Manager-Oberfläche.
Hier kann man bequem eine Domain und die notwendigen Records erzeugen. Auf der Seite https://pdnsmanager.lmitsystems.de ist das unter Documentation nachvollziehbar beschrieben.
Für die Domain habe ich eine Subdomain benutzt um die Nameserver-Einstllungen vereinfachen zu können. Es bleibt dann:
dyn.zzz-server.de NS dns.zzz-server.de dns.zzz-server.de A 85.214.xxx.yyy
Man kann beim PDNS Manager auch über die API updaten:
wget -O /dev/null "http://server-domain.de/pdnsm/api/remote.php?action=updateRecord&domain=debacher.dyn.client-domain.de&id=1&password=assword&content=1.2.3.9"
Leider kann man die IP-Adresse nicht vom Script selber ermitteln lassen, sondern muss sie mit angeben. Eventuell passe ich mir da die Datei remote.php einmal an.