分享

Your own DDNS Server with Ubuntu and Plesk / silenced.eu

 Dead n Gone 2014-09-22

Annoyed by new regulations of dyndns.org to log in every 30 days to maintain your free account, I decided to host my own dynamic DNS server. I have a rented vServer running Ubuntu 10.04 LTS with Plesk 11.5 on top. Plesk is also the reason that none of the existing tutorials I found did entirely help me.

To outline what I am doing to accomplish this service:

Most tutorials describe how to create/manipulate DNS zones with the BIND server. This however is not a convenient option if you are running plesk. Plesk is doing most of the DNS configuration automatically based on the domains you maintain in the web interface. Therefore we make use of all the magic Plesk is doing by manipulating not the actual zone/key files, but the records in the Plesk database. After that it is just a matter of telling Plesk to update its records and voila: All the DNS records have been created/updated for us.

To update the database we build a little PHP website which can be called from the host you want to maintain the dyn dns record for. In my case that’s a FritzBox 7390 router.

So what do you need for this tutorial?

  • An Ubuntu server (most other Linux distributions should do the trick as well)
  • Plesk. I am using 11.5 but I very much assume that older versions will also work.
  • At least one own domain. You could also split the different parts below into different domains.
Now lets get started:
  1. First of all we need a MySQL database user that’s allowed to read and write in the Plesk database. Obviously we need to be careful when touching this database to not do any damage to our Plesk configuration. Therefore we create a new user which has very limited privileges. This user can only access the table dns_recs of Plesks psa database. That’s where Plesk stores its DNS information. So your user might look as follows:
    GRANT SELECT, UPDATE (time_stamp, displayVal, val) ON `psa`.`dns_recs` TO 'dnsupdateuser'@'localhost';
  2. The important columns are host, type and val as you will see later
  3. Now, I assume that you have your domain configured and running in Plesk. Lets call it
  4. Now we create the first subdomain in Plesk which will host our dyndns server. Let’s call it dyn.. You could also host this directly on you domain if you like. E.g. /dyn/
  5. We create one subdomain for each dynamic host you want to facilitate. We call ours home.
  6. By default Plesk does not enable the DNS for the sub domain but manages the entries together with the main domain. So we need to enable this manually: Select the subdomain –> DNS –> Enable DNS-Service
  7. Now we see a lot of DNS entries which Plesk creates automatically. We can get rid of most of them. So we delete all entries except for the A record. This is the important one. I am not really sure about the NS records, so I kept them :-) If anyone has a comment there, please let me know.
  8. Currently the A record will show the IP of your server. However, this is the one we will later update to point to your dyn host.
  9. In the webspace of the dyn. subdomain first of all we create a .htaccess and .htpasswd to password protect this entire domain. The .htaccess might look like this:
    AuthType Basic
    AuthName "Login"
    AuthUserFile /var/www/vhosts///.htpasswd
    Require valid-user
    Options +Indexes
  10. Now comes the update page. This is a rather simple php page with not much of an output. As it will be the only page in the webspace we can call index.php. Of course you can customize this any further if you like. You should be able to understand most of the code yourself so just a few remarks:
    • We take the IP from the requestor as our new to-be IP.
    • Check if the requested domain (as a GET parameter) is one of our dyn domains
    • Check the plesk database if the IP has changed since the last update
    • If it has changed, we alter the database record.
    • To notify the actual updater – a cron job – we create a watched file
    • In the sucess event I echo “good [IP]” since this seems to be what makes the FritzBox recognize the update without any errors.
<?php

include 'mysql_config.php';

$dynDomains = array('home.', 'garden.', 'dog.');

$newIP = $_SERVER['REMOTE_ADDR'];
$DoUpdateFile = "updatefile/doupdate";

if(!isset($_GET['domain'])){
    die('Parameter "domain" not set');
}
// Check if the requested domain is in our list of domains we want to keep updated.
if(! in_array($_GET['domain'], $dynDomains)){
    die('Requested domain is not in the list of maintained dyn domains.');
}

// Check if IP is really an IP (should always be the case, but just to be safe...)
if($newIP == "" || !preg_match_all("/(\d{1,3}\.){3}\d{1,3}/", $newIP, $matches )){
    die();    
}    

// We need to append a dot (.) to the end of the requested domain
$dyndns = $_GET['domain'] . '.';

$query = "SELECT id, val FROM dns_recs WHERE host = '$dyndns' AND type = 'A';";

$result = mysql_query($query);
$row = mysql_fetch_assoc($result);

$rowId = $row['id'];
$oldIP = $row['val'];

if($oldIP == $newIP){
    echo "No update. IP has not changed since last update: " . $newIP;
    echo "good ".$newIP;
    die();
}

// Update IP
$updateQuery = "UPDATE dns_recs SET val = '$newIP', displayVal = '$newIP' WHERE id = $rowId;";

$updated = mysql_query($updateQuery ) or die (mysql_error());

$updateDomain = $_GET['domain'] . ";";
# Create do-update file to notice cron job to update the DNS entry
file_put_contents($DoUpdateFile, $updateDomain, FILE_APPEND);

echo "good ".$newIP;

?>

 
And as requested in the comments my mysql_config.php file

<?php

$server = "localhost";
$user_server = "dnsupdateuser";
$password_server = "yourPassword";
$database= "psa";

$verbindung = mysql_connect ("$server", "$user_server", "$password_server")
or die ("connection failed. User and/or password incorrect.");

mysql_select_db("$database")
or die ("Database does not exist");

?>
    1. Make sure you created the directory (updatefile/) and  your webserver user (mostly called www-data) has sufficient permissions to write in it.
    2. That done, the last step is to create a script to run the Plesk update. I decided for an hourly cron job, but you might prefer something else.
    3. My script called updatedynamicdns resides in /etc/cron.hourly. Make sure it is executable.
    4. The script checks if the doupdate file exists and if so, it runs the plesk dns update command for each hostname in the update file: /opt/psa/admin/bin/dnsmng --update hostname This reloads the DNS config for the specified host from the database and recreates the zone/key files. Afterwards the updatefile is deleted.
#!/bin/sh

# log file
logfile='/var/log/dynamicdns/dnsupdate.log'

# update file
updatefile='/var/www/vhosts//dyn./updatefile/doupdate'

## do things

# check the update file exists. If not, do not update DNS record

if [ ! -s $updatefile ]
then
#       echo "$(date -R) Update file doesn't exist. No update necessary. Quitting." >> "$logfile"
       exit
fi

domainList=`cat $updatefile`

# Split domain list by ;
IFS=';' read -ra domainsArr <<< "$domainList"

# Iterate over all domains in the array and update them one by one
for domain in "${domainsArr[@]}"; do

echo "$(date -R) Updating DNS entry for $domain" >> "$logfile"

# Update DNS entry for $domain via PLESK
/opt/psa/admin/bin/dnsmng --update $domain

done

# delete update file
rm $updatefile

 

    1. After all that done you can test you own DDNS: Open the update page in your web browser, e.g. http://dyn./?domain=home.. (You should see the login page first)
    2. Check if the doupdate file was created correctly. If so, you can either wait for the hourly cron job to run or start the script yourself.
    3. Now check the file /var/named/run-root/var/home. There you should now see the new IP instead of the IP of your server.
    4. After that it is just a matter of time until your DNS record has been properly propagated and you can reach your home from anywhere :-)

I hope you found my first tutorial useful! If you have any questions, remarks or suggestions for improvement, please let me know in the comments.

44 thoughts on “Your own DDNS Server with Ubuntu and Plesk”

  1. This works really great!
    Jetzt aber weiter auf Deutsch:
    Durch Zufall bin ich heute über dieses HowTo gesto?en. Ich habe schon l?nger nach einem Solchen System gesucht und bin nicht richtig fündig geworden. Danke für die ganze Mühe, die du da rein gesteckt hast!
    Ein paar Gemeinheiten sind dan aber doch noch in den Details verborgen: die mysql_config.php hat mich etwas ge?rgert – auch wenn mir schon vorher klar war, wie sie Aussieht – vergessen habe ich sie im ersten Moment trotzdem.
    Das Shellscript l?uft nur in der bash – mit sh hats nur seltsame Fehler ausgegeben. Das ging ja alles noch.
    Was wirklich gedauert hat ist die Einstellung bei Strato selbst – nicht nur in PLESK muss der eigene Nameserver aktiviert sein, nein auch in der Verwaltungsoberfl?che von STRATO muss die statische IP für diese Subdomain deaktiviert werden. Als ich das durchschaut hatte gings dann wunderbar (zumindest nach der Wartezeit bis sich der alte NS aktualisiert hatte). Nochmal danke für dieses tolle Stück Arbeit – einen solchen L?sungsansatz habe ich schon lange gesucht, aber bisher gab es nichts vergleichbares im Netz.

    • Danke für deinen Comment!
      Mein Server l?uft bei HostEurope, dort hatte ich keine Probleme mit dem Nameserver au?erhalb von Plesk. Daher aber gut zu wissen, dass es wohl nicht überall so einfach geht.

    • Wie genau kann man bei Strato die statische IP für diese Subdomain deaktivieren?

    • Hab deinen Post bei meiner Problemmeldung total überlesen. Bin auch bei Strato, aber finde in der Domainverwaltung keinen Menüpunkt der mich weiterbringen k?nnte. Kannst du ggf. etwas detaillierter beschreiben wo sich die Option befindet?

      Viele Grü?e!

  2. Des Weiteren solltest du vielleicht noch hinschreiben, wie man den mysql-User anlegt?

  3. Das Shellskript enth?lt ebenfalls Fehler:

    >
    <
    Kein Hinweis auf das Logfile /var/log/dynamicdns/dnsupdate.log’

    • Hallo Frank,
      die Darstellungsfehler sind irgendwelche Encoding Probleme im WordPress. Nach einigen Versuchen hatte ich das aufgegeben.

      Das Ganze ist hier etwas verkürzt. Mit wenigen Grundkentnissen sollte man aber den Rest erg?nzen k?nnen.

  4. Ausserdem vermisse ich die Info wie man das in der Fritzbox konfiguriert.

  5. was kommt in die mysql_config.php?

    • Hallo Ronny,
      bittesch?n, die mysql_config.php:

      < ?php

      $server = "localhost";
      $benutzer_server = "dnsupdateuser";
      $passwort_server = "yourPassword";
      $datenbank = "psa";

      $verbindung = mysql_connect ("$server", "$benutzer_server", "$passwort_server")
      or die ("connection failed. User and/or password incorrect.");

      mysql_select_db("$datenbank")
      or die ("Database does not exist");

      ?>

  6. Hello Sebastian!
    I’m really not familiar with php or scripting so i had to ask. Thank you very much for the file, everything is working now as expected! Great, i really appreciate what you have done here.

    I’d like to add a few points to your tutorial:

    1 – Perhaps not really neccessary, but in the dns zone ‘’ i created a NS and A record for the dyndns subzone, like this:
    ns.home.example.con A 1.2.3.4
    home. NS ns.home.

    In the zonefile of ‘home.’ i only have the corresponding A record and three NS records that belong to my ISP, which in my case only run as slaves and in case of an update, get notified by my Plesk host, which works as a hidden primary server.
    A WHOIS on ‘home.’ also shows the newly created NS additionally to the other three.

    2 – index.php line 41: I needed to add some single quote marks around $newIP in order to make it work, else a SQL syntax error is thrown

    3 – I needed to type out the expressions < + > in the cronjob script to . Else syntax error.

    4 – Fritzbox Update URL: http://dyn./?domain=home.
    User/Password like in the .htpasswd file
    Domain: home. (or something else, doesn’t matter)

    System is debian6 with PSA11.5.30#41 and is a vserver at Hetzner.
    Perhaps you can complete the tut with this information some time, as there is a huge demand for a solution like this as dyn.com recently announced discontinuation of their former free service.

    Thanks

    • Hi Ronny,

      thanks a lot for your comments and additions. I will update the post when a find the time… In the meantime they are visible in your comment :)
      I got some issues with WordPress and encoding, thats why some signs are not properly shown and some error occurs from the scripts above.

      Cheers,
      Sebastian

  7. Hi,

    I just wanted to do something similar and then found your solution. Great!
    The update script is updating the DB properly, but after running /opt/psa/admin/sbin/dnsmng –update my.domain.de the DNS config seems unchanged. Also no output by this script. I ran it manually because I had problems running you shell script even when correcting > and < signs. (parameter -a at read wasn’t allowed), but nevermind. I only need one domain and I can hardcode it.

    I only have /var/named/run-root/var/my.domain.de file, in this file AND /etc/named.conf there is the IP of my server, but in Plesk DNS settings menu I see the home IP which was written into the psa database.

    Anyone who had similar problems?

    • Hi,
      which version of Plesk are you on? It the IP was properly changed in the database I am not really sure why the update command won’t work. I didn’t have any issues in this regard.

      Sebastian

    • I’m getting an error on

      # Split domain list by ;
      IFS=';’ read -ra domainsArr >>> “$domainList”

      ./ddns_mod: line 22: syntax error near unexpected token `>’
      ./ddns_mod: line 22: `IFS=';’ read -ra domainsArr >>> “$domainList”‘

  8. Hi Sebastian, greate job!

    I use PLESK 11.5 and i have made the following changes:

    To verify the changes the file for the host config is located under /var/named/chroot/var/home.

    updatedynamicdns: The path to dnsmng is /usr/local/psa/admin/bin/dnsmng
    Don’t forget to create the log dir (md /var/log/dynamicdns)

    index.php: I don’t use a mysql_config.php, at the beginning of the file, I inserted

    $db = mysql_connect(‘localhost’,’dnsupdateuser’,’xxxxxx’) or die(“Database error”);
    mysql_select_db(‘psa’, $db);

    I create the database user with a password:
    GRANT SELECT, UPDATE (time_stamp, displayVal, val) ON `psa`.`dns_recs` TO ‘dnsupdateuser’@’localhost’ IDENTIFIED BY ‘XXXXX';

    That’s all. Thanks.
    Sven

  9. Hi, Sebastian

    Thank you very much for this piece of code and clever idea. I was looking for something like this for months.

    Once sorted out some syntax issues, everything is working fine. Perhaps the worst thing is my dd-wrt and Inadyn protocol, that is failing sometimes. But that’s another history…

    Thanks again, best regards

  10. Works great on HE server.

    Only one thing:
    Using a dual stack IPv4/v6 Domain for the update script, $_SERVER['REMOTE_ADDR'] may return a wrong value, if your system or request-setting prefers IPv6.

    One solution would be a modified script (e.g. to a dyn.com compatible syntax using ?hostname=…&myip=…).
    Or simply use a IPv4-only domain for the script.

    • Thanks for the remark, I am not yet on IPv6 so I didn’t think of that.

      • No problem.

        After testing around for a while, I noticed another point:
        It works without calling dnsmng from cron. Just set SOA records appropiate (TTL 5min, refresk 60min, retry 30min or something like this), update the datebase and wait some minutes… So the cron script creates a nice logfile.

        I also added simple multiuser support by using a multidimensional array associated with die username ($_SERVER['REMOTE_USER']), just 2 little changes:
        $dynDomains = array("user1" => array('dyn1.', 'dyn2.'),
        "user2" => array('dyn3.', 'dyn4.'));
        [...]
        if(! in_array($_GET['domain'], $dynDomains[$_SERVER['REMOTE_USER']])) { [...]

  11. Hallo Sebastian,
    ich hatte dir ja heute eine EMail geschickt, aber ich schreibe es einfach auch einmal hier rein, sollten andere ?hnliche Probleme haben ….

    – Genutzt wird ein Speedport W700V

    So schauen die Konfigurationsm?glichkeiten im Menü aus: http://www./uploads/routerw7003v9ojctbp5.jpg

    Leider funktioniert das .php Script nicht, wobei es sich evtl. auch nur um einen Fehler handelt bei der Konfiguration des Routers. Genutzt wird laut Angabe vom Router das Protokoll von “dyndns.org V2″.

    – Was tr?gt man anhand deiner Beispiele wo ein ?
    – Ist das Script dafür überhaupt zu nutzen ?

    • Hallo Sascha,

      das Script oben ist nicht nach dem dnydns V2 Protokoll erstellt. Ist ist darauf ausgelegt, dass es lediglich per HTTP Request aufgerufen wird – wie es bspw. die Fritzboxen bieten. Daher wird es vermutlich mit dem Speedport Router leider nicht funktionieren.

      Falls du doch eine L?sung finden sollte, poste sie gerne hier!

      Grü?e,
      Sebastian

  12. I’m getting an error on

    # Split domain list by ;
    IFS=’;’ read -ra domainsArr >>> “$domainList”

    ./ddns_mod: line 22: syntax error near unexpected token `>’
    ./ddns_mod: line 22: `IFS=’;’ read -ra domainsArr >>> “$domainList”‘

  13. A true explorer!

    Easy, simple, and works!

    Many thanks!

    Rui

  14. Hi,

    coole Anleitung. Hab’s eben mal ausprobiert. Updates funktionieren soweit. Allerdings wird bei mir keine Updatefile generiert und das Script schreibt auch kein log. Irgendeine Idee?

    Habe auch einen Server bei hosteurope mit Plesk 11.5

    Gru?
    Sebastian

    • Du musst sicher stellen das die Verzeichnisse existieren und die n?tige Berechtigung gesetzt ist!

      doupdate

      # log file
      logfile='/var/log/dynamicdns/dnsupdate.log'

      # update file
      updatefile='/var/www/vhosts//dyn./updatefile/doupdate'
      ---8<---

      Alternativ kannst Du im Anschluss an diese Zeilen auch folgendes einfügen:

      ---8<---
      #check for directory
      if [ ! -d "$logdir" ]; then
      mkdir $logdir
      fi
      #check for logfile
      if [ ! -f "$logfile" ]; then
      touch $logfile
      fi

      #check for directory
      if [ ! -d "$upddir" ]; then
      mkdir $upddir
      fi
      #check for updatefile
      if [ ! -f "$updatefile" ]; then
      touch $updatefile
      fi
      ---8<---

  15. Sebastian, I get a syntax error here…

    # Split domain list by ;
    IFS=';’ read -ra domainsArr <<< "$domainList"

    Error = 25 : Syntax error: redirection unexpected.

    Any ideas?

    Thanks

    Steve C

  16. Hallo,
    Erstmal vielen Dank dafür! L?uft das so auch unter Plesk 12?

  17. Updatefile is working, logfile is okay and the ip (manual php-file-request, fritzbox-access wont work as it seems…dont know why) is set in the database/DNS-settings. But if i want to connect to my FritzBox via https://Subdomain.Domain.net, i get a Plesk-page as result. I’am using Plesk 12.0.18 @ Strato.

    Any Idea ? Meinetwegen auch in deutscher Sprache :)

    • Hi,
      hast du
      a) Die Website Funktionalit?t für diese Subdomain deaktviert
      b) Ist dein Fritzbox Admininterface auf Port 443 erreichbar?

      Grü?e,
      Sebastian

      • a) Ja
        b) Ja

        Bei der Domain habe ich ‘Hosyting-Typ’ auf ‘Kein Webhosting’ gesetzt und ‘Website-Status’ auf ‘aktiv’. Was mich halt verwirrt. Wenn ich die URL aufrufe und dabei die Domain übergebe tr?gt das Script die IP in die Datenbank ein. In der DNS-Zone habe ich dann die IP meiner Box unter dem HOST der Subdomain als Eintragstyp A stehen. Die Fritzbox kann ich dennoch nicht erreichen, was denke mal daran liegt, dass unter HOST die Subdomain nochmals aufgeführt ist und auf den Eintragstyp NS verweist.

        In meiner Fritzbox habe ich die Einstellung Dynamic DNS-Anbieter gew?hlt und die vollst?ndige Updateurl (ohne Parameter) mit den Zus?tzlichen Informationen eingetragen. Erhalte jedoch von der FritzBox immer den Fehler “Dynamic DNS-Fehler: Fehler bei der DNS-Aufl?sung des Domainnamens”. Das hilft mir aber nur bedingt weiter das Problem einzugrenzen.

        Bin gerade etwas ratlos wo es h?ngt.

        • Hm, ich nehme mal an, dass wenn du einen nslookup auf deine subdomain machst, du die ip es Servers bekommst? Versuch das mal von deinem Rechner und vom Server selbst

          • Vom Server aus erhalte ich 2x ‘Got SERVFAIL reply ‘ in den ersten 2 Ausschriften. Die letzte Zeile findet die Subdomain nicht. Von einer Linux-VM aus gibt es direkt nach dem lookup keine Fehler, die letzte Ausschrift findet die Subdomain aber auch nicht. Hatte zuvor noch nix mit nem nslookup zu tun.

            Grü?e

          • Wenn du (egal ob Windows oder Linux) “nslookup home.” eingibst, solltest du etwas bekommen in der Richtung:

            Non-authoritative answer:
            Name: home.
            Address: 123.45.67.89

  18. l?uft auch unter plesk 12

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多