Skip to content

Instantly share code, notes, and snippets.

@arnu515
Last active August 3, 2021 06:04
Show Gist options
  • Save arnu515/701598ced79fb61d2c762c999d1fb8d4 to your computer and use it in GitHub Desktop.
Save arnu515/701598ced79fb61d2c762c999d1fb8d4 to your computer and use it in GitHub Desktop.

DigitalOcean Domains Dynamic DNS

Automatically updates a domain (registered with DigitalOcean)'s record with the current IP of the machine. Ideal for home-labs with dynamic IPs who want to avoid services like NoIP or can't use cloudflare domains.

Designed for Linux

How to use

Requires: Python 3.6.9 or later, requests library installed.

Download the source code of this gist by using the download button, and extract the zip file.

Configure:

Update the variables in main.py that have capital letters. Update your domain name, record name and DigitalOcean API Key.

Run:

Make the file executable with

chmod +x main.py

Run the file with

./main.py

# OR
python3 main.py

This will only run this once. Be sure to use something like crontab to automatically run this every once-in-a-while. Once every 30 minutes is a good call. We don't want to spam any APIs!

Be sure to star this if it was useful!

#!/usr/bin/python3
import requests
import sys
import os
import json
# File where the IP will be stored. (To avoid unnecessraily updating the domains)
# Be sure to change ithis on Windows, this is not a valid path there!
IP_FILE_PATH="/tmp/my_public_ip.txt"
# Name of the domain registered in digitalocean
# Don't include any https, subdomains or slashes
# e.g. example.com
DOMAIN_NAME="myamazinghomelab.ml"
# Name of the domain record
# e.g. test will become test.example.com if your DOMAIN_NAME is example.com
# Use @ to make it the whole domain
RECORD_NAME="@"
# Create a `read` and `write` API Key on digitalocean and paste it here
API_KEY="272f801110b690f999d6e2852d286a0dd64f1151c1eb9d522b5deb4d2dd569db"
if not IP_FILE_PATH or not DOMAIN_NAME or not RECORD_NAME or not API_KEY:
print("Invalid configuration")
sys.exit(1)
def get_ip():
# Get the IP
try:
ip = requests.get("https://ifconfig.me").content.decode()
if not os.path.exists(IP_FILE_PATH):
with open(IP_FILE_PATH, "w") as f:
f.write(ip)
else:
with open(IP_FILE_PATH, "r+") as f:
file_ip = f.read().strip()
if ip == file_ip:
print("No need to update IP")
sys.exit(0)
return
f.seek(0, 0)
f.truncate(0)
f.write(ip)
return ip
except Exception as e:
print("An error occured while fetching IP")
print(e)
# Peacefully exit
sys.exit(0)
return
def delete_domain_record(domain):
print("Deleting existing domain record " + RECORD_NAME + "." + DOMAIN_NAME)
domain_id = domain.get("id")
res = requests.get("https://api.digitalocean.com/v2/domains/" + DOMAIN_NAME + "/records/" + str(domain_id), headers={
"Authorization": "Bearer " + API_KEY
})
res.raise_for_status()
def update_domain_record():
try:
ip = get_ip()
res = requests.get("https://api.digitalocean.com/v2/domains/" + DOMAIN_NAME + "/records", headers={"Authorization": "Bearer " + API_KEY})
domains = json.loads(res.content.decode()).get("domain_records")
for domain in domains:
if domain.get("name").lower() == RECORD_NAME.lower() and domain.get("type").lower() == "a":
delete_domain_record(domain)
print("Creating new domain record " + RECORD_NAME + "." + DOMAIN_NAME)
data = {
"type": "A",
"name": RECORD_NAME,
"data": ip,
"ttl": 30
}
res2 = requests.post("https://api.digitalocean.com/v2/domains/" + DOMAIN_NAME + "/records", json=data, headers={"Authorization": "Bearer " + API_KEY})
res2.raise_for_status()
print("IP was updated!")
except Exception as e:
print("An error occured while updating domain")
print(e)
# Peacefully exit
sys.exit(0)
return
update_domain_record()
requests==2.26.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment