PHP IP Update Script


#1

Hi,

I wrote a script to auto-update your IP in the DNS Zone if it has been changed. It can be used on Linux (through systemd or cron), Windows (through Task Scheduler) and Mac too probably but I don’t have one so I can’t test it, or tell you how to do it.

You can use them for multiple domains, just copy it and fill in the needed fields and run them.

The only thing you need is PHP with curl enabled in php.ini.

domain.tld-updater.php (just call them after your domain so it’s easy to remember which one is which)

<?php
$headers = [ 
    'X-Auth-Email: YOUR_EMAIL_ADDRESS',
    'X-Auth-Key: YOUR_CLOUDFLARE_AUTH_KEY',
    'Content-Type: application/json'
];

$domain = "example.com";
$record = "sub.example.com";
$ip = file_get_contents('https://api.ipify.org');

$data = [
    'type' => 'A',
    'name' => $record,
    'content' => $ip,
    'ttl' => '1',
    'proxied' => true
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, "https://api.cloudflare.com/client/v4/zones?name=$domain");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$result = curl_exec($ch);
if (curl_errno($ch)) {
    exit('Error: ' . curl_error($ch));
}
curl_close ($ch);

$json = json_decode($result, true);

$ZoneID = $json['result']['0']['id'];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, "https://api.cloudflare.com/client/v4/zones/$ZoneID/dns_records?name=$record");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$result = curl_exec($ch);
if (curl_errno($ch)) {
    exit('Error: ' . curl_error($ch));
}
curl_close ($ch);

$json = json_decode($result, true);

$DNSID = $json['result']['0']['id'];

$old_ip = $json['result']['0']['content'];

if ($old_ip === $ip) {
    echo "CloudFlare IP: $old_ip" . PHP_EOL;
    echo "Current IP: $ip" . PHP_EOL;
    echo "The IP doesn't have to be changed!" . PHP_EOL;
}
else {
    echo "CloudFlare IP: $old_ip" . PHP_EOL;
    echo "Current IP: $ip" . PHP_EOL;
    echo "The IP has to be changed!" . PHP_EOL;
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, "https://api.cloudflare.com/client/v4/zones/$ZoneID/dns_records/$DNSID");
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");  
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $result = curl_exec($ch);
    if (curl_errno($ch)) {
        exit('Error: ' . curl_error($ch));
    }
    echo "The IP has changed from $old_ip to $ip!" . PHP_EOL;
}

domain.tld-updater.service (just call them after your domain so it’s easy to remember which one is which)

[Unit]
Description=Update domain.tld to current IP if needed

[Service]
Type=oneshot
ExecStart=/usr/bin/php /opt/domain.tld-updater.php

domain.tld-updater.timer (This will trigger the update command every minute)

[Unit]
Description=Update domain.tld entry in CloudFlare every minute

[Timer]
# Time to wait after booting before we run first time
OnBootSec=1min
# Time between running each consecutive time
OnUnitActiveSec=1m
Unit=domain.tld-updater.service

[Install]
WantedBy=timers.target

Don’t forget to enable the and start the timer with: sudo systemctl enable domain.tld-updater.timer and sudo systemctl start domain.tld-updater.timer.

On Windows just create a task in Task Scheduler which will run every minute (or 5).

If you see a error or fault in my script please tell me!


DNS Query for selfhosted domain
#2

Thank you @zjaakie


#3

Works Find! thanks @zjaakie


#4

Hi.

It suddenly stopped working since 1 month.
it says:
The IP has changed from x.x.x.x to y.y.y.y

but it actually never updated.
any idea how to debug this to check where things went wrong?


#6

The current IP is x.x.x.x
the script fetches it correctly.
but it can never update it to the second one (y.y.y.y)

and when i run the script again, the same old ip is being fetched, and the same message comes that the IP has changed.


#8

Does anything show up in the Audit Log in your Cloudflare dashboard? If so, compare it to a log entry from when it was working.


#9

Yes, the first one works and fetches the IP through GET.
but the PUT does not work, there is no error,


#10

the script:
$result = curl_exec($ch);
if (curl_errno($ch)) {
exit('Error: ’ . curl_error($ch));
}
does not get executed, meaning there is no error.
i am not sure where to debug, since nothing is shown on the dashboard…


#11

i did add this to the script:
$ip = file_get_contents(‘https://api.ipify.org’);
$ip = ‘1.1.1.1’;

after i run, here is what it shows:

[email protected] ~# /usr/bin/php /etc/ddclient/a.php
CloudFlare IP: 218.250.87.245
Current IP: 1.1.1.1
The IP has to be changed!
The IP has changed from 218.250.87.245 to 1.1.1.1!
[email protected] ~#
[email protected] ~#
[email protected] ~# /usr/bin/php /etc/ddclient/a.php
CloudFlare IP: 218.250.87.245
Current IP: 1.1.1.1
The IP has to be changed!
The IP has changed from 218.250.87.245 to 1.1.1.1!
[email protected] ~#
[email protected] ~#
[email protected] ~# /usr/bin/php /etc/ddclient/a.php
CloudFlare IP: 218.250.87.245
Current IP: 1.1.1.1
The IP has to be changed!
The IP has changed from 218.250.87.245 to 1.1.1.1!
[email protected] ~#


#12

I would like to update if someone had the same issue:
i echoed the error and it was:
“DNS Validation Error”,“error_chain”:[{“code”:9021,“message”:“Invalid TTL. Must be between 120 and 2,147,483,647 seconds, or 1 for automatic”}

so i removed the TTL record and it worked!

$data = [
‘type’ => ‘A’,
‘name’ => $record,
‘content’ => $ip,
‘proxied’ => false
];


#13

I will update the script ASAP with a check if the IP has been updated.


#14

Since I can’t edit the first post, I will post the update overhere. I also marked this post as answer so people wont use the old one!

Changes:

  • Using curl to fetch the current IP and if internet is down exit with a error.
  • Replaced the TTL option without quotes
  • Added a check if nothing went wrong while replacing the IP.

This should be working if not reply :slight_smile: