ISPConfig Dynamic DNS
22 May 2019
3 minute read

[recipe, sysadmin]: How to create and update a DDNS entry in ISPConfig

If you manage your DNS server(s) with ISPConfig you may want a dynamic entry that gets updated automatically every time the target host changes its IP address.

Doing so in ISPConfig is quite straight forward: we can use the ISPConfig SOAP API to update an existing record with a PHP script to be run frequently by the target host.

In this recipe I will consider updating an A record.

  1. First we need to create a remote user on the ISPConfig master server to authenticate, and grant it remote access and some functions:

    In “System -> Remote User” add a new remote user, enable remote access and grantDNS zone functions” and each DNS functions corresponding to the type of record you want to update: so if you want to update an A record you must grant the generic “DNS zone functions” and the “DNS a functions”

  2. We then have to write a PHP script that will make a SOAP function call to the ISPConfig endpoint. The target host, or the host executing the script must have the PHP SOAP module installed.

    Create the update.php script as follow:

    <?php
    require('config.php');
    
    if ($argc<3) {
    	print "Usage: php ./update.php HOST DOMAIN [IP]\n";
    	print "If not given, the ip address will be queried from icanhazip.com\n";
    	die();
    }
    // First parameter: hostname of DNS entry
    $ddns_host = $argv[1];
    // Second: domain name of DNS zone
    $domain = $argv[2];
    // If third parameter is present
    if ($argc>3) {
    	// Third parameter: IP address of target host
    	$ip = $argv[3];
    // Otherwise
    } else {
    	// Figure out the public IP of this host:
    	$ip = trim(file_get_contents("http://icanhazip.com/"));
    	if (filter_var($ip, FILTER_VALIDATE_IP) === false) {
    	die("Unable to retrieve public IP address (icanhazip.com returned $ip)\n");
    	}
    }
    
    print("Setting DDNS host $ddns_host.$domain to IP $ip\n");
    
    // Using the SOAP module initialize a SoapClient
    $client = new SoapClient(null,
    	array('location'   => $soap_location,
    		'uri'        => $soap_uri,
    		'trace'      => 1,
    		'exceptions' => 1));
    
    try {
    	// Login to SOAP server
    	$session_id = $client->login($soap_user, $soap_password);
    
    	// Grab DNS zone ID
    	$zone_id = $client->dns_zone_get_id($session_id, $domain);
    	// Grab DNS zone
    	$zone = $client->dns_zone_get($session_id, $zone_id);
    	// Grab DNS records
    	$records = $client->dns_rr_get_all_by_zone($session_id, $zone_id);
    	
    	// Find right record: hostname must match and type must be A
    	$dns_record = null;
    	foreach ($records as $rec) {
    		if ($rec['type']=='A' && $rec['name']==$ddns_host) {
    			$dns_record = $rec;
    		}
    	}
    	// If no record found
    	if (is_null($dns_record)) {
    		//Logout from SOAP server
    		$client->logout($session_id);
    		die("Unable to find DNS record for host $ddns_host in domain $domain on the server...\n");
    	}
    	// If IP stored in record is different from current IP
    	if ($dns_record['data'] != $ip) {
    		// Set new IP
    		$dns_record['data'] = $ip;
    		// Increment record serial number
    		$dns_record['serial'] = $dns_record['serial']+1;
    		// Update modified record in DNS server
    		$client->dns_a_update($session_id, null, $dns_record['id'], $dns_record);
    		
    		// Increment zone serial number
    		$zone['serial'] = $zone['serial'] + 1;
    		// Update modified zone in DNS server
    		$client->dns_zone_update($session_id, 0, $zone_id, $zone);
    		
    		print("Successfully set DNS entry for host $ddns_host in domain $domain to $ip.\n");
    	// Otherwise
    	} else {
    		print("IP address of $ddns_host.$domain already set to $ip.\n");
    	}
    	
    	//Logout from SOAP server
    	$client->logout($session_id);
    	
    } catch (SoapFault $e) {
    	die('SOAP Error: '.$e->getMessage()."\n");
    }
    
    ?>
    

    Create the config.php as follow:

    <?php
    $soap_location = 'https://ispconfig.example.com:8080/remote/index.php';
    $soap_uri = 'https://ispconfig.example.com:8080/remote/';
    $soap_user = 'username';
    $soap_password = 'password';
    
  3. Schedule the execution of update.php

END.