Skip to content

Instantly share code, notes, and snippets.

@christr
Forked from mhussain/update-dns.sh
Last active May 26, 2024 04:00
Show Gist options
  • Save christr/9de75da7fd1ffbd1aa4f0b33316fff8c to your computer and use it in GitHub Desktop.
Save christr/9de75da7fd1ffbd1aa4f0b33316fff8c to your computer and use it in GitHub Desktop.
Linode dynamic DNS updating script
#!/bin/bash
# Modified by Chris Richardson (https://github.com/christr and https://twitter.com/christr77) on 09/20/2020
# Previous versions of this script don't work because they hadn't been updated since 2012. There are now more steps involved to set this up.
# This script update is based on information found here: https://developers.linode.com/api/v4/domains-domain-id-records-record-id/#put
# You first must find out the domain ID and resource ID numbers. In order to do this follow the steps below.
# 1. Create a Linode API Key through your account profile at https://cloud.linode.com/dashboard. Give it rights to read/write to domains only.
# 2. From a shell run the following command: LINODE_API_KEY=[insert API key from step 1 here]
# 3. Run the following command to get the domain ID number for the domain you want to manage: curl -H "Authorization: Bearer $LINODE_API_KEY" https://api.linode.com/v4/domains/
# 4. From a shell run the following command: DOMAIN_ID=[insert domain ID number from step 3 here]
# 5. Run the following command to get the resource ID number for the subdomain you want to manage: curl -H "Authorization: Bearer $LINODE_API_KEY" https://api.linode.com/v4/domains/$DOMAIN_ID/records/
# 6. From a shell run the following command: RESOURCE_ID=[insert resource ID number from step 5 here]
# 7. Run the following command to verify the current settings for this resource: curl -H "Authorization: Bearer $LINODE_API_KEY" https://api.linode.com/v4/domains/$DOMAIN_ID/records/$RESOURCE_ID
# 8. Use the information collected from these commands to complete the variables below in this script.
LINODE_API_KEY=
DOMAIN_ID=
RESOURCE_ID=
NAME=
function resource_update {
curl -H "Content-Type: application/json" \
-H "Authorization: Bearer $LINODE_API_KEY" \
-X PUT -d '{
"type": "A",
"name": "'$NAME'",
"target": "'$WAN_IP'",
"priority": 0,
"weight": 0,
"port": 0,
"service": null,
"protocol": null,
"ttl_sec": 120,
"tag": null
}' \
https://api.linode.com/v4/domains/$DOMAIN_ID/records/$RESOURCE_ID
}
WAN_IP=`curl -s ifconfig.me/ip`
if [ -f $HOME/.wan_ip.txt ]; then
OLD_WAN_IP=`cat $HOME/.wan_ip.txt`
else
echo "No file, need IP"
OLD_WAN_IP=""
fi
if [ "$WAN_IP" = "$OLD_WAN_IP" ]; then
echo "IP Unchanged"
else
echo $WAN_IP > $HOME/.wan_ip.txt
echo "Updating DNS to $WAN_IP. Results from Linode are displayed below."
resource_update
fi
@demaniak
Copy link

demaniak commented Jun 7, 2023

If I'm reading the docs right, it looks like you could possibly avoid the drama around obtaining the WAN IP.

From the docs:

The target for this Record. For requests, this property’s actual usage and whether it is required depends on the type of record this represents:

A and AAAA: The IP address. Use [remote_addr] to submit the IPv4 address of the request. Required.

So, looks like you can literally replace the value of target with the string literal [remote_addr] (literally that, no substitution), then linode will use the IP of the request.

Note: I have not (yet) tested this.

But seems these people came to the same conclusion.

@demaniak
Copy link

demaniak commented Jun 7, 2023

One more note: setting ttl_sec to zero seems to make linode take the setting to the default used by your domain.
For a dynamic IP situation, this is probably not want you want.

@christr
Copy link
Author

christr commented Jun 7, 2023

If I'm reading the docs right, it looks like you could possibly avoid the drama around obtaining the WAN IP.

From the docs:

The target for this Record. For requests, this property’s actual usage and whether it is required depends on the type of record this represents:

A and AAAA: The IP address. Use [remote_addr] to submit the IPv4 address of the request. Required.

So, looks like you can literally replace the value of target with the string literal [remote_addr] (literally that, no substitution), then linode will use the IP of the request.

Note: I have not (yet) tested this.

But seems these people came to the same conclusion.

Thank you. These are some excellent suggestions. I actually prefer the current method myself because I like that no update is even initiated to Linode if the IP hasn't changed. The information has already been collected if an update is necessary, so I prefer to pass that same variable. In some cases dynamic IPs can stay the same for months or years. I haven't tried [remote_addr] myself, but will certainly keep it in mind.

In regards to TTL. I prefer a TTL of 0, as that domain would only be used for the given setup. Others may be of differing opinions though, and that's certainly understandable.

@hausmanconsulting
Copy link

hausmanconsulting commented Jun 7, 2023

I actually prefer the current method myself because I like that no update is even initiated to Linode if the IP hasn't changed.

Back in the day, my DDNS provider (not Linode) would penalize too many API calls where nothing changed. Interesting that Chris chimed in in that thread about simply using remote_addr. I guess Linode didn't care about API calls that didn't update anything (and I wonder if Akamai will feel the same way).

The other benefit to the bit of logic there is that we get an entry in syslog when the IP changes, which can come in handy for troubleshooting ISP issues like modem/ONT resets, firmware updates, etc.

The TTL point is a good one; I can confirm this behavior (TTL of 0 sets it to "default" in DNS manager rather than literally zero seconds). According to Linode the default ttl is 86400 seconds, which as @demaniak noted is probably not what we want. I've just set mine to 120s and it updates the TTL from "Default" to 2mins.

@christr
Copy link
Author

christr commented Jun 7, 2023

That's a good point I didn't consider on the TTL. I modified the script to do 120. Thank you both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment