Linking your subdomain to dynamic ip

Short guide to setup your own DynDNS Service. As result, your subdomain ddns.example.com points to an ip of your choice. This guide is tested on ubuntu server 17.10, on other systems path etc. may differ.

Requirements

Guide

Create config folder

apparmor by default allow read and write for bind in /var/lib/bind.

	mkdir /var/lib/bind/zones
	mkdir /var/lib/bind/zones/keys

Create Zone File /etc/bind/zones/ddns.example.com.zone

	$ORIGIN .
	$TTL 10 ; 10 seconds
	ddns.example.com	IN SOA  ns1.example.com. example.com. (
		27	; serial
		10800		; refresh (3 hours)
		3600		; retry (1 hour)
		604800		; expire (1 week)
		10		; minimum (10 seconds)
	)
	$TTL 3600		; 1 hour
		NS		ns1.example.com.

Create keys

	cd /var/lib/bind/zones/keys
	dnssec-keygen -b 512 -a HMAC-MD5 -v 2 -n HOST ddns.example.com.

Read key file

Copy the key for later use.

	grep Key /var/lib/bind/zones/key/Kddns.example.com.+xxx+yyyyy.private
	> Key: GENERATED KEY

Add key and zone to /etc/bind/named.conf.local

	key ddns.example.com. {
		algorithm "HMAC-MD5";
		secret "GENERATED KEY";
	};

	zone "ddns.example.com" {
		type master;
		file "/var/lib/bind/zones/ddns.example.com.zone";
		allow-update{
			key ddns.example.com;
		};
	};

Grand bind user and www-data group access

Read access for www-data is necessary for following update script, may not be required in other solutions.

	chown -R bind:www-data /var/lib/bind/zones
	chmod -R g+r /var/lib/bind/zones

Restart bind9

	service bind9 restart

Set DNS Records for domains

It depends on the hoster on how to do that and usually takes some time to be applied (up to 48h).

	ns1	A		[server-ip]
	ddns	NS		ns1.example.com.

Example php update script

This is a small example update php script to call e.g from your router. Important is the call of nsupdate, feel free to adopt other resolutions.

	<?php

	// username param
	$username = $_GET['username'];

	// password param
	$password = $_GET['password'];

	// password hash
	$hash = ''; // password_hash('yourpw', PASSWORD_DEFAULT);

	// valid username
	$valid_username = 'yourusername';

	// check username password combination
	if ($username != $valid_username || !password_verify($password,$hash)) {
		echo "wrong username or password";
		exit(0);
	}

	// ip param
	$ip = $_GET['ip'];

	// if no ip given, get request ip
	if (!isset($ip)) {
			$ip = $_SERVER['REMOTE_ADDR'];
	}

	// simple ip regex check
	if (!preg_match("/^(\d{1,3}\.){3}\d{1,3}$/", $ip ) {
		echo "invalid ip format.";
		exit(0);
	}

	// data for nsupdate
	$data = "<<EOF
			server example.com
			zone ddns.example.com
			update delete ddns.example.com A
			update add ddns.example.com 10 A $ip
			show
			send
			EOF";

	// keyfile
	$key = '/var/lib/bind/zones/key/Kddns.example.com.+xxx+yyyyy.private';

	// execute update
	exec("nsupdate -k $key $data", $cmdout, $ret);

	// return result
	foreach($cmdout as $cmd) {
		echo $cmd . "<br />";
	}

	if ($ret != 0) {
		echo "errorcode: " . $ret;
	}

	?>