Dynamic DNS with Google Cloud DNS

Dynamic DNS with Google Cloud Platform is much simpler than it seems. Join me on this journey of ensuring that my ownCloud server is always accessible using a Google Cloud DNS A record.

NOTE: I have updated this tutorial and the supporting code to Python 3.9. All requirements are also updated to the current latest version at the time.

The Problem

I run an OwnCloud server at home on a Raspberry Pi to provide for a central storage location for profile data and music, etc for the entire house. We have a reasonably good internet connection, however it is a dynamic IP address which is not fantastic for pointing a DNS name at with any sort of reliability.

There are plenty of solutions out there for Dynamic DNS like dyndns.com, etc. But I want a solution that works with my Google Cloud Platform project that currently hosts my domain name.

Thoughts

  • The solution needs to be secure, ideally using Google service accounts to update DNS records.
  • It also needs to be reliable. There is no point building this fantastic solution if it doesn’t actually do the job it is required to do.
  • I want it to run on the Raspberry Pi that is currently running the OwnCloud software.

The Solution

The solution I came up with is very simple and is run reliably via a cron job on any Linux distro. Using some basic python code that I have created and Google Cloud Functions

Setup Google Cloud DNS

If you don’t already have a Google Cloud Platform (GCP) account, head over to https://console.cloud.google.com and sign up to receive USD$300 in credit to play around with and test out the platform. Once you are in create your first project and note down the project id for later. Head to Network Services and then Cloud DNS on the left side to create your first domain name. From there, update the name servers at your domain registrar to the ones provided by Google Cloud DNS.

Create a Service Account

You will need to generate a service account with permissions to modify Cloud DNS as well as write logs and pull from your source code repository. Since there are a myriad of these around, and Google have covered it much better than I, check theirs out here https://cloud.google.com/iam/docs/creating-managing-service-account-keys The permissions I have used are: DNS Administrator, Logs Writer

Clone google-dns-updater from GitHub

git clone https://github.com/ianbrown78/google-dns-updater.git

Fork the above repo to your github account and replicate it to Google Source Repository since it will be there anyway.

Mirror your new fork to Google Source Repository by following this guide: https://cloud.google.com/source-repositories/docs/mirroring-a-github-repository

Create an app key

Open a terminal window and type the following: (Assuming you are on a Mac or Linux machine) echo "import secrets; print(secrets.token_urlsafe(64))" | python

Take note of this key as it will be the key you require to connect to the updater.

Configure GCP Cloud Function

Create a new cloud function and setup the following info:

  • Name: A meaningful name for you.
  • Memory: I have allocated 128MB. This should be plenty.
  • Runtime: Python 3.9
  • Source Code: Cloud Source repository
  • Repository: The name Google gave the mirror. Mine is ‘github_ianbrown78_google-dns-updater’
  • Branch: master
  • Directory with source code: /src
  • Function to execute: main

Then set the following Environment Variables:

  • dnsZoneName: The DNS Zone name you gave your zone.
  • dnsDomain: The domain name.
  • ttl: 3600 or your chosen Time To Live for DNS records.
  • project: The project id you noted down earlier.
  • app: The app key you generated earlier.

Now click Deploy at the bottom, and if all goes well, you should have a cloud function up and running that you can use to update your DNS records.

Test the app to ensure it is updating the correct record.

Testing the function requires knowledge of using Postman or cUrl to construct a post request to the cloud function. Whilst this is beyond the scope of this quick tutorial, here is an example cUrl request:

curl -X POST \
    -d 'host=<Host name>&ip=<IP Address>&key=<API service key>' \
    http://localhost:5000/

Note that the host value must be the entire hostname. eg. test.ianbrown.id.au. Be careful that you include the period (.) at the end or the hosts won’t match.

Deploy the cronjob

Now that we have the function up and running, we need to add a cronjob to our Raspberry Pi to call it from our new IP.

The cronjob should look something like this:

IPADDRESS=`curl ipecho.net/plain`
*/5 * * * * curl -X POST -d 'host=test.ianbrown.id.au.&ip=$IPADDRESS&key=abc123' https://asia-east2-ian-test.cloudfunctions.net/google-dns-updater >/dev/null 2>&1