Skip to content
This repository was archived by the owner on Mar 17, 2020. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 41 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,62 @@ Digital Ocean Dynamic DNS-Updater

Purpose:
--------
Allows the dynamic updating of an 'A' record that is managed by Digital Oceans DNS server.
Allows the dynamic updating of DNS records that are managed by Digital Oceans DNS server.


Liberated From:
---------------
The original script and idea (i.e. the brains behind the whole thing) was lovingly taken from ['pushingkarma.com'](http://pushingkarma.com/notebook/dynamic-dns-your-home-pc-using-digitaloceans-api/).
I forked this code from Ben Squires' original project at https://github.com/bensquire/Digital-Ocean-Dynamic-DNS-Updater

However it was written using Python v2, I had installed v3 so adapted the script as best I could. I then decided it would be cool to also convert it into PHP (I know at least 1 other person that would find it useful) so that's what I did, enjoy!
He, in turn, improved the original code which came from ['pushingkarma.com'](http://pushingkarma.com/notebook/dynamic-dns-your-home-pc-using-digitaloceans-api/).


The changes I've made from Bens version;
* Add additional parameter so an @ record can be updated.
* Add the ability to choose which type of record to update (A/CNAME etc)
* Add an optional command to be called upon update of the IP (for example; https://github.com/Siftah/vpnuk_smartdns_client)
* Amended the way the error handling works so that it's more coherent when called from a cronjob, it now only creates output if the debug DEFINE is set to TRUE, there's a real error, or it updates the IP address. All other times it will be silent.
* Extracted some of the config into a seperate config.php to make pushing updates to GitHub easier without sharing my personal config with the world ;)

Use Case:
------
Given you have a domain whose DNS is hosted with Digital Ocean and wish to dynamically update a domain record based on your current IP, for example, where you have a dynamically assigned IP address from your internet service provider.

This script can be called from a crontab once every 15 minutes, where it detects a change in your IP it will update the record of your choice to point to your new IP address.

For example, I have siftah.net pointing to my current home IP address.

Usage:
------
Provide your API key, domain you want to update and the 'Record' for that domain and schedule the script to run however
often you want (using for example the Windows Scheduler or a cron job).
Get your Personal Access Token from Digital Ocean: ['Personal Access Token'](https://cloud.digitalocean.com/settings/applications).

The PHP script has been designed to be called as a command line tool, or from a crontab. Some config is passed into it in the form of CLI parameters, for example:

E.g:
`php updater.php accessToken domain record type [command]`

My home server has a sticky IP, I want to be able to connect to it remotely using:
were;
* *accessToken* is your ['Personal Access Token'](https://cloud.digitalocean.com/settings/applications)
* *domain* is the domain name you want to update (e.g: joebloggs.com).
* *record* is the value of the a-record you want to update (e.g: home).
* *type* is the type of record A/CNAME/etc
* *command* is an optional command which will be called when the IP has been updated. It can be omitted if not required.

home.joebloggs.com
Only the fifth parameter is optional, all others are required.

I'd create an 'A' record in DO with the hostname 'home', under the domain 'joebloggs.co.uk' and while I was there
retrieve my ['Personal Access Token'](https://cloud.digitalocean.com/settings/applications).
You can also create a cronjob with contents to suit your timing and personal access token:
`*/15 * * * * $HOME/scripts/Digital-Ocean-Dynamic-DNS-Updater/updater.php personal_access_token siftah.net @ A [$HOME/scripts/vpnuk_smartdns_client/vpnuk_smartdns_client.php]`

Where personal_access_token is your own access token.

config.php
------
I experienced some issues with the IP check page which Bens original script contained, I therefore created my own. If you want to do this you can edit the config.php page to point to your own URL. The regular expression matches any IP address contained in the response, so the format of the page is flexible. You can also use the following PHP snippet;

Example Usage:
--------------
The php script has been designed to be called as a command line tool. Config is passed into it in the form of CLI parameters, for example:
`<html><head><title>Current IP Check</title></head><body>Current IP Address: <?php
echo $_SERVER['REMOTE_ADDR'];
?></body></html>`

php updater.php accessToken domain record

python updater.py accessToken domain record

were 'accessToken' is your ['Personal Access Token'](https://cloud.digitalocean.com/settings/applications), 'domain' is the domain name you want to update (e.g:
joebloggs.com) and 'record' is the value of the a-record you want to update (e.g: home).
Then update the following DEFINE to point to it's URL:
`DEFINE('CHECK_IP', "http://82.196.x.xx/ip.php");`


Thanks to:
----------
@surfer190, @nickwest, @gnoeley, @ryanwcraig for adding additional features, testing code and feedback.
20 changes: 20 additions & 0 deletions config.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
/*
If you want to create your own page which returns the IP address,
perhaps with a fixed ip (hosted on Digital Ocean) you can use the
following in a .php page;

<html><head><title>Current IP Check</title></head><body>Current IP Address: <?php
echo $_SERVER['REMOTE_ADDR'];
?></body></html>

Then update the following DEFINE to point to it's URL:
*/
DEFINE('CHECK_IP', "http://checkip.dyndns.org:8245");

//The URL for the API, should not need changing.
DEFINE('API_URL', "https://api.digitalocean.com/v2/");

//Timeout value for accessing the IP page.
DEFINE('CURL_TIMEOUT', 60);
?>
59 changes: 43 additions & 16 deletions updater.php
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
#! /usr/bin/env php
<?php
require_once('config.php');

/**
* Debug a little better.
*/
define('DEBUG', false);
function debug_echo($input) {
if (DEBUG==true) {
echo($input."\r\n");
}
}

/**
* Return the contents of a page (DO only uses GET requests for its API...)
*
Expand Down Expand Up @@ -64,7 +76,7 @@ function getRecord($page = null)
$dataJson = json_decode($data, true);

foreach ($dataJson['domain_records'] as $record) {
if ($record['name'] === RECORD) {
if ( ( $record['name'] === RECORD ) && ( $record['type'] === TYPE ) ) {
return $record;
}
}
Expand Down Expand Up @@ -111,6 +123,9 @@ function setRecordIP($record, $ipAddress)

$data = curl_exec($ch);
curl_close($ch);
execOnSuccess();
echo 'IP Address successfully updated from: ' . $record['data'] . ' to: ' . $ipAddress . "\r\n";

return ($data !== false);
}

Expand All @@ -127,35 +142,47 @@ function setRecordIP($record, $ipAddress)
throw new Exception('3rd parameter (A Record) is missing.');
}

if (!isset($argv[4])) {
throw new Exception('4th parameter (Type) is missing.');
}


if (!isset($argv[5])) {
function execOnSuccess (){
//noop
}
} else {
function execOnSuccess (){
exec($GLOBALS['argv'][5]);
}
}

DEFINE('ACCESS_TOKEN', $argv[1]); //Digital Ocean Personal Access Tokens (read & write)
DEFINE('DOMAIN', $argv[2]); //joebloggs.co.uk
DEFINE('RECORD', $argv[3]); //home
DEFINE('CURL_TIMEOUT', 15);
DEFINE('CHECK_IP', "http://checkip.dyndns.org:8245");
DEFINE('API_URL', "https://api.digitalocean.com/v2/");
DEFINE('TYPE', $argv[4]); //CNAME

echo 'Updating ' . RECORD . '.' . DOMAIN . ': ' . date('Y-m-d H:i:s') . "\r\n";
echo 'Fetching external IP from: ' . CHECK_IP . "\r\n";
debug_echo('Updating ' . RECORD . '.' . DOMAIN . ': ' . date('Y-m-d H:i:s') . "\r\n");
debug_echo('Fetching external IP from: ' . CHECK_IP . "\r\n");
if (($ipAddress = getExternalIp()) === false) {
throw new Exception('Unable to extract external IP address');
}

echo 'Fetching Record ID for: ' . RECORD . "\r\n";
debug_echo('Fetching Record ID for: ' . RECORD . "\r\n");
if (($record = getRecord()) === false) {
throw new Exception('Unable to find requested record in DO account');
}

echo 'Comparing ' . $record['data'] . ' to ' . $ipAddress . "\r\n";
debug_echo('Comparing ' . $record['data'] . ' with type ' . TYPE . ' to ' . $ipAddress . "\r\n");
if ($record['data'] === $ipAddress) {
throw new Exception('Record ' . RECORD . '.' . DOMAIN . ' already set to ' . $ipAddress);
}

echo 'Updating record ' . $record['name'] . '.' . DOMAIN . " to " . $ipAddress . "\r\n";
if (setRecordIP($record, $ipAddress) === false) {
throw new Exception('Unable to update IP address');
}
debug_echo('Record ' . RECORD . '.' . DOMAIN . ' already set to ' . $ipAddress);
} else {
debug_echo('Updating record ' . $record['name'] . '.' . DOMAIN . " to " . $ipAddress . "\r\n");
if (setRecordIP($record, $ipAddress) === false) {
throw new Exception('Unable to update IP address');
}
}

echo 'IP Address successfully updated.' . "\r\n";
} catch (Exception $e) {
echo 'Error: ' . $e->getMessage() . "\r\n";
exit(1);
Expand Down