Custom Dynamic DNS Service on Arch Linux

Setup Custom Dynamic DNS Service on Arch Linux

DDNS or Dynamic Domain Name System service makes reliable remote access without a static IP. The setup consists of the client script that runs on the Linux machine and the back-end service that is hosted on a remote server. The client periodically sends it’s own external IP to the remote server. The remote server will then be able to redirect to the dynamic IP of the local client. If you do not have a remote server with a static IP to host your custom service you can instead setup No-IP DDNS on Arch Linux. The advantage of a custom Dynamic DNS server is that it remains under your control and there are no limitations as with free services.

 

Local Client IP Update Script

Create a service script.

sudo nano /usr/local/bin/ddns.sh

 

Copy the shell code and save.

#! /bin/bash

URL=$(curl -u dom:********** -A "Mozilla" dominicm.com/ddns/update.php)

if [ $URL = "success" ]
then
 echo "Success"
else
 echo "Failure"
 # notify user?
fi

If no credentials are configured the -u or --user option can be omitted. Progress output is hidden with the -s or --silent option. To prevent the 406 Not Acceptable error a user agent should be specified with -A or --user-agent option. In the event of failure to connect or to obtain an external IP address the user could be notified via several methods like email.

 

Set execute permissions on the script.

sudo chmod +x /usr/local/bin/ddns.sh

 

Run the shell script manually.

/usr/local/bin/ddns.sh

The client script updates the remote DDNS server with the possibly new IP address using a GET request.

 

Start DDNS Script

Create a systemd service file.

sudo nano /etc/systemd/system/ddns.service

 

Copy the systemd service script and save.

[Unit]
Description=Custom DDNS Update Service
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/ddns.sh

[Install]
WantedBy=ddns.timer

 

Start the service.

sudo systemctl start ddns

 

Run DDNS on a Schedule

Traditionally cron jobs had been used to execute timed tasks. However since cron tool is not installed by default and systemd is, it makes a compelling alternative.

 

Create a systemd timer.

sudo nano /etc/systemd/system/ddns.timer

 

Copy the systemd timer script and save.

[Unit]
Description=Runs DDNS Update script every 10 minutes

[Timer]
OnBootSec=1min
OnUnitActiveSec=10min
Unit=ddns.service

[Install]
WantedBy=multi-user.target

 

Start the timer script.

sudo systemctl start ddns.timer

 

Enable the systemd timer to run on boot.

sudo systemctl enable ddns.timer

 

Remote Server IP Update Script

Install PHP and Apache Web Server

 

Create a directory within the site root.

mkdir /public_html/ddns

 

Change current directory to the newly created directory.

cd /public_html/ddns

 

Create PHP update script on the remote web server.

nano update.php

 

Copy the PHP code and save.

<?php

$authenticated = false;
$message = "";

function get_ip_address()
{
 // Check for shared internet/ISP IP
 if (!empty($_SERVER['HTTP_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_CLIENT_IP']))
 return $_SERVER['HTTP_CLIENT_IP'];
 
 // Check for IPs passing through proxies
 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
 // Check if multiple IP addresses exist in variable
 $ip_list = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
 foreach ($ip_list as $ip) {
 if ($this->validate_ip($ip)) {
 return $ip;
 }
 }
 }
 if (!empty($_SERVER['HTTP_X_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_X_FORWARDED']))
 return $_SERVER['HTTP_X_FORWARDED'];
 if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
 return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
 if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && $this->validate_ip($_SERVER['HTTP_FORWARDED_FOR']))
 return $_SERVER['HTTP_FORWARDED_FOR'];
 if (!empty($_SERVER['HTTP_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_FORWARDED']))
 return $_SERVER['HTTP_FORWARDED'];
 
 // Return unreliable IP address since all else failed
 return $_SERVER['REMOTE_ADDR'];
}

//Ensures an IP address is both a valid IP address and does not fall within a private network range.
function validate_ip($ip)
{
 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
 return false;
 }
 return true;
}

if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
 $user = $_SERVER['PHP_AUTH_USER'];
 $pass = $_SERVER['PHP_AUTH_PW'];
 if ($user == 'dom' && $pass == '*************') {
 $authenticated = true;
 }
}

if (!$authenticated) {
 header('WWW-Authenticate: Basic realm="ddns"');
 header('HTTP/1.0 401 Unauthorized');
 $message = "Authentication failed!\n";
} else {
 $file = 'ip.txt';
 $old_ip = file_get_contents($file);
 $new_ip = get_ip_address();
 
 if ($old_ip == $new_ip) {
 // IP did not change
 $message = "success";
 } else {
 // IP was changed.
 if(file_put_contents($file, $new_ip) !== false){
 $message = "success";
 } else {
 $message = "failure";
 }
 }
}

print $message;

?>

The PHP script accepts GET requests from the local client and attempts to get the correct IP address. It then saves the IP address to a text file if it has changed and returns a status message to the client. Do not forget to change the username and password values.

 

Remote Server DDNS Redirect Script

Create PHP redirect script on the remote web server.

nano index.php

 

Copy PHP code and save.

<?php

$authenticated = false;

if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])){
 $user = $_SERVER['PHP_AUTH_USER'];
 $pass = $_SERVER['PHP_AUTH_PW'];
 if ($user == 'dom' && $pass == '***********'){
 $authenticated = true;
 }
}

if (!$authenticated){
 header('WWW-Authenticate: Basic realm="ddns"');
 header('HTTP/1.0 401 Unauthorized');
 print "Authentication failed!\n";
}
else {
 $file = 'ip.txt';
 $ip = file_get_contents($file);

 if($ip != ""){
 header('Location: http://' . $ip);
 }
 else{
 $message = "Dynamic IP is not available.\n";
 }
}

?>

The PHP script accepts GET requests from the local client and saves the received IP address to a text file if it has changed. Do not forget to change the username and password values.

 

Use Custom DDNS Server

The IP of the local client should now be saved on the remote server and updated every 10 minutes. To access the local client go to the path of the DDNS scripts on the remote server.