So you have your own fixed-IP server, maybe a VPS you rent for your basic web hosting services, but your own home gets dynamic IPs from your ISP, and you want to update a subdomain on your server with your home’s dynamic IP (Because why would you not use your own domain name for your DDNS needs?). Well, look no further!
This is really going to be an instruction set for my future self more than anything else, so please proceed at your own risk.
I always start off my server installations by installing Webmin/Virtualmin on it. If you don’t use them, and extensively use your server for hosting purposes, you already know about this stuff more than I do, and can easily follow along these sets of instructions, but please do try out Virtualmin, moving your existing Apache server is as easy as a simple copy-paste. If you don’t use your server for website hosting, you can try out Webmin (it is a GUI wrapper for various administrative tools in Linux). If you plan to use your server for website hosting but haven’t started working on it, you should definitely try Virtualmin (it automatically installs Webmin and LAMP stack to host your websites) for your one-stop server controls. From this point on, I will assume you have a functioning Virtualmin instance running on your server serving your domain (e.g. domain.tld); or alternatively, your server hostname is configured with an FQDN, you have proper glue records/nameservers pointing to your server, and you use bind9 for your DNS zone management.
The first question you need to ask yourself is, how you want to configure DNS for your dynamically changing IP. Do you want to run another Virtualmin server and give it complete control over its domain (your ddns subdomain)? Or do you just want your IP to be resolved by your subdomain address? I personally prefer to have another Virtualmin running (I had an old Optiplex lying around, what choice did I have?) on my gateway, so I will assume you want the same (if you just want your IP resolved, follow along anyway, the setup is quite similar).
Our plan of attack would be to keep an existing Virtual Server running on Virtualmin (or a Bind9 domain master zone) as the parent DNS zone, with nameserver records (and DNSSEC keys) for your subdomain pointing to your dynamically changing IP. In short, you own the domain: domain.tld and want your dynamically changing IP to be resolvable to sub.domain.tld, but you also want the server on sub.domain.tld to be able to issue deeper level domains (e.g. sub2.sub.domain.tld) independent of your server at domain.tld.
To do that, you need to add the the following entries to your DNS record of your virtual server.
sub.domain.tld. IN NS ns.sub.domain.tld. ns.sub.domain.tld. IN A dynamically.changing.ipv4.addr ns.sub.domain.tld. IN AAAA dynamic:changing:ip:v6::addr
This is an example of glue records, you probably have one with your own domain name registrar.
If you just want your IP resolved, all you need are the following entries in your DNS records.
sub.domain.tld. IN A dynamically.changing.ipv4.addr sub.domain.tld. IN AAAA dynamic:changing:ip:v6::addr
And our primary concern is to update the desired records automatically with updated IPs, because they change. To know our WAN facing IP, we need to keep a php file on our VPS. In Virtualmin, go to File Manager and create a new file called ip.php
Now edit the file and write the following
<?php $ip = $_SERVER['REMOTE_ADDR']; ?> <?php echo $ip . '\n'; ?>
Non-Virtualmin Bind9 users, make a new file on your VPS named ip.php so that it’s resolvable by https://domain.tld/ip.php and write in the php script mentioned above.
Now that we have a way to know our public IP, test it in your client (the computer with dynamically assigned IP) gateway’s terminal:
curl -4 https://domain.tld/ip.php
You should see your public IPv4 address. For your public IPv6 address, do:
curl -6 https://domain.tld/ip.php
If for some reason you cannot do the above, maybe your VPS is IPv4 only or IPv6 only, you are welcome to use my service at
curl -4 https://checkip.meghadeep.casa curl -6 https://checkip.meghadeep.casa
Please keep your requests limited to 1 per minute, I run fail2ban to automatically ban offenders (including myself).
Now, we need to actually change our domain records, since we finally know our WAN IPs. Virtualmin lets us do that very easily with command line interface. We just need to run the following python script in our client gateway (the computer with dynamically assigned IPs) every few minutes to achieve that.
If you don’t use Virtualmin, and want to update your Bind9 records, you can try something like the following, I am not entirely confident whether I understand nsupdate’s connection option fully.
Before you run this script, make sure you create a text file in your client gateway’s /etc/netplan/ directory with the name ddns-old.txt (and also ddns-bat.txt if you use nsupdate method). You might also need to install paramiko module for python in that machine:
pip3 install paramiko
And you would want to make the script executable:
chmod +x /path/to/file.py
After you run the script once:
./path/to/file.py or python3 /path/to/file.py
you just need to add one static NS entry in your domain.tld DNS zone (in your VPS), and you’ll be set.
If you just want an IP address update, you don’t need to add any NS record, and you will need to change “ns.sub” in my script to “sub”.
You can do that with Virtualmin -> Choose Appropriate Virtual Server -> Server Configuration -> DNS Records -> Create NS Record.
If you don’t use Virtualmin, add the following in your Bind9 DNS record in the appropriate domain.tld zone.
sub.domain.tld. IN NS ns.sub.domain.tld.
Now that we have proper glue records, let’s automate our script in our client machine. We can do that easily with Cron. Open up terminal:
sudo crontab -u root -e
Append the following at the end to run the script every 5 minutes to check for our dynamic IP.
*/5 * * * * ./path/to/file.py
On your client gateway, register your machine with a fully qualified domain name (e.g. gateway.sub.domain.tld) as its hostname, and make a new Virtual Server with sub.domain.tld address (equivalent to making a new master zone with address sub.domain.tld in your local Bind9 instance). Your nameserver is ns.sub.domain.tld. Go to Virtualmin -> Addresses and Networking -> Dynamic IP Update, and enable it; this would allow Virtualmin to automatically update your virtual server IP address. If you just want your IP resolved, and don’t have a Virtualmin instance running on your gateway, you won’t need to do this. And that’s it, you’re golden!