Update A record for domain using OVH API
I recently noticed that the external IP of my broadband connection doesn’t actually change very often, once every one or two months. So I figured I could just point one of my domains to my ‘home server’; no need to use a ‘dynamic DNS’ provider.
If you use the ‘Pong script’ which I posted earlier, then this Python script can update the A record of your domain’s nameserver to point to your current external IP address, given that you use the OVH nameservers. Just call it with a cron job.
Note: You need install python-ovh:
pip install python-ovh
And you need to generate API access keys for the script: https://eu.api.ovh.com/createToken/
For this step be careful to grant three permissions:
GET /domain/zone/<YOUR DOMAIN>/record
GET /domain/zone/<YOUR DOMAIN>/record/*
PUT /domain/zone/<YOUR DOMAIN>/record/*
And here’s the script:
import json
import ovh
import sys
import socket
import re
DOMAIN = "example.com"
OVH_ENDPOINT = "ovh-eu"
OVH_APP_KEY = ""
OVH_APP_SEC = ""
OVH_CON_KEY = ""
# Using https://floki.cc/2019/10/netcat_pong
# (adjust get_current_ip() method if you're using
# something else)
PONG_HOST = "External IP"
PONG_PORT = 12345
def get_current_ip():
"""
Get the current external IP using the 'PONG_HOST'.
:return: See above
"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((PONG_HOST, PONG_PORT))
data = s.recv(1024)
s.close()
new_ip = data.decode("utf-8").strip()
if not re.compile("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$").match(new_ip):
raise Exception("Could not get current IP")
return new_ip
def get_current_arecord_ip(client):
"""
Get the current IP and record ID which is set in the
A record of the nameserver for the domain
:param client: The OVH API client
:return: (record_id, ip) tuple
"""
path = "/domain/zone/{}/record".format(DOMAIN)
result = client.get(path,
fieldType='A',
subDomain='' # you can use a subdomain too
)
if len(result) != 1:
raise Exception("Could not get current A record IP")
record_id = result[0]
path = "/domain/zone/{}/record/{}".format(DOMAIN,record_id)
result = client.get(path)
return record_id, result['target']
def update_arecord(client, record_id, ip):
"""
Update the A record with the given ID with the provided IP
:param client: The OVH API client
:param record_id: The ID of the A record
:param ip: The IP to update the record with
:return:
"""
path = "/domain/zone/{}/record/{}".format(DOMAIN,record_id)
result = client.put(path,
target=ip
)
def main():
ip = get_current_ip()
client = ovh.Client(
endpoint=OVH_ENDPOINT,
application_key=OVH_APP_KEY,
application_secret=OVH_APP_SEC,
consumer_key=OVH_CON_KEY,
)
record_id, old_ip = get_current_arecord_ip(client)
if ip != old_ip:
print("Updating A record to IP {}".format(ip))
update_arecord(client, record_id, ip)
else:
print("No update required")
if __name__ == "__main__":
main()