Last week I was asked whether I knew how to set up a dyndns server. Well, I didn’t at that time, but I did some research. This is what I found.

First, problem description.

  • At home,you have a FritzBox or similar DSL router that lets you specify a dnydns server.
  • For some reason, you don’t want to use one of the predefined services, e.g. dyndns.org.
  • But you have a webserver somewhere in the internet with a domain and some webspace where you can run PHP scripts.
  • You don’t care whether the real DNS entry (domain name service) is changed, as long as your customers or whoever gets to see the right page. So this is not going to be a real dynamic DNS entry, but just some sophisticated redirect mechanism.

My FritzBox allows to specify a user-defined server to use for DynDNS. But I didn’t know how it would notify this server about my home IP address. I couldn’t find any documentation about this anywhere. So I wrote a script to print all the information about the request into a log file. This is what I found:

  • The FritzBox lets you specify username and password for the dyndns server, but neither is transmitted in the request parameters (GET or POST). This led me to think of HTTP authentication instead (authentification is needed if you want to control who can set the IP address for dyndns).
  • Also, the FritzBox’s IP address is not transmitted in the request parameters, but this is superfluous as you can get it from the server parameters ($_SERVER["REMOTE_ADDR"] in PHP).

So what do you need?

First, a .htaccess file to specify authentication for the dyndns script:

# put the name of the PHP script you're about to write here: 
<Files "dyndns.php">
   AuthType Basic
   AuthName "Authentication for clients that want to connect to this dyndns server." 
   # the name of the password file (see below): 
   # Specify the absolute path, or the path relative to the server root! 
   AuthUserFile /full/path/my-passwords
   # the username of your choice: 
   require user dyndnsuser
</Files>

You need to create the my-passwords file using the htpasswd utility that comes with the apache webserver installation. To create a password file called “my-passwords” with a user “dyndnsuser”, use this command on the shell command line:

htpasswd -c my-passwords dyndnsuser

It will let you type a password.

Now only clients with the correct username/password authentication will be able to call the dnydns.php script. Such as your DSL router.

Then, the script itself, here called dyndns.php:

<?php
# this include file contains some helper functions: 
include("dns-functions.inc");    

if ( readIpFromFile() == getIpFromRequest()) {
  header("HTTP/1.1 304 IP address didn't change", true, 304);
  message("no change in IP, address is " . getIpFromRequest() . "\n");
} else {
  if (writeIpToFile()){
    header("HTTP/1.0 200 OK", true, 200);
    message("change successful, new address is " . getIpFromRequest() . "\n");
  } else {
    header("HTTP/1.0  500 Error writing file or similar", true, 500);
    message("error writing file or other.\n");
    exit;
  }
}
?>

The dns-functions.inc include file with the helper functions:

<?php
# name of the file where the IP address will be stored: 
$ip_file = "./ip";

# write debug stuff to a logfile
function message($text) {
  $file = fopen("dyndns.log", "a");
  fwrite($file, $text);
  fclose($file);
}

# get IP address from request parameter, or if none is given, 
# from the REMOTE_ADDR parameter
function getIpFromRequest() {
  # just in case the IP _is_ in the request parameters, you never know: 
  if (isset($_GET["ip"])) {
    return $_GET["ip"];
  } 
  if (isset($_POST["ip"])) {
    return $_POST["ip"];
  } 
  # if it's not, we get it from the remote address parameter: 
  return $_SERVER["REMOTE_ADDR"];
}

# read the IP address from the file. 
function readIpFromFile() {
  global $ip_file;
  if(file_exists($ip_file)) {
    if(filesize($ip_file)>0) {
      $file = fopen($ip_file, "r");
      $ip = fread($file, filesize($ip_file));
      fclose($file);
      return $ip;
    }
  }
}

# write the IP to the file. will return 'false' if there is a problem. 
function writeIpToFile()     {
  global $ip_file;
  $file = fopen($ip_file, "w");
  $result = fwrite($file, getIpFromRequest());
  fclose($file);
  return result;
}
?>

This PHP stuff was inspired by Michi’s dyndns script.

You may want to add the following to your .htaccess file to prevent people from spying out your setup:

<Files "dns-functions.inc">
  deny from all
</Files>

<Files "ip">
  deny from all
</Files>

<Files "my-passwords">
  deny from all
</Files>

All the stuff you have written so far can be placed anywhere on your webspace, as long as you specify the complete URL path to the dyndns.php script as the “update URL” in the Fritzbox Dyndns configuration.

So now the FritzBox can pass it’s IP address to your webserver. In my FritzBox’s log file, there was no message if this process was successful, I only saw log entries if something went wrong (in which case I had to look at the dyndns.log file the script writes on the webserver to check what happened).

But what then? How do we set up the webserver to actually direct requests to the FritzBox’s IP? You will need a directory and/or a subdomain on your server which to use for the redirect, so you can type something like fritzbox.mywebserver.com or myserver.com/fritzbox to be redirected to your FritzBox.

There are several possibilites to do the redirect.

1. Return a “Location” header informing the client that the document he’s looking for is somewhere else.
to do this, you’ll have to create an index.php script in the directory or at the subdomain that looks like this:

<?php
# specify complete path to the include file if it's in another directory: 
include("dns-functions.inc");    
$newurl= "http://" . readIpFromFile();
header("Location: $newurl");
?>

Whenever a client goes to fritzbox.mywebserver.com, it will be redirected to your FritzBox’s current IP address (URL in the browser’s location bar will change).

2. Use a frame redirect. This is a little bit more subtle since the IP address will not show up in the browser’s location bar, but on the other hand, if the client navigates within the page, the browser’s location bar will not show that, either. It will always just show the main domain: fritzbox.mywebserver.com

In this case, the index.php needs to look like this:

<?php
include("dns-functions.inc");    
$newurl="http://" . readIpFromFile();
?>
<html>
<frameset rows="100%">
  <frame src="<? echo $newurl; ?>">
</frameset>
<noframes>
  <body>Please follow <a href="<?echo $newurl; ?>">link</a>!</body>
</noframes>
</html>

3. Use Rewrite Rules. This will make the forwarding look most professional as the client/browser will only see the main domain and the redirect will happen on the webserver (like with a proxy). Drawback is that POST parameters are not passed on.

For the Rewrite Rules to work, you’ll have to adapt the dyndns.php script to make a change to the .htaccess file whenever a new IP is set. I haven’t tried this yet but I’ll let you know as soon as I figured it out :-)


2 Responses to “How to set up your own dyndns server (simple!)”

  1. 1

    schlumpf that was a very interesting read, im a big old noob but now I feel less empowered by all the schlupfness going on at this post. Im was going to give it a try but wanted to ask of you figured out changing htcaccess file when new IP is set?

    Thanks

    Bill (May 23rd, 2012 at 00:24)
  2. 2

    Hi Bill,
    thanks for yout question. I did try the .htaccess/Rewrite Rule thing, but I noticed that you need to do a lot of configuration for the webserver itself (enable proxy etc), something people won’t be able to do if they only have the webspace, but no access to the server configuration. That’s why I didn’t follow up on this.

    schlumpf (May 25th, 2012 at 05:13)

Any comments? Or questions? Just leave a Reply: