Using Azure as a Dynamic DNS provider for your home server

When hosting services from your home, you will want to use a Dynamic DNS (DDNS) entry in order to map your ever-changing IP address to a hostname you can use to access those services. For instance, will point to your IPv4 (or IPv6) address. There are providers noip and Duck DNS, but below is a method to use an Azure DNS zone and a script to update the IP on a regular basis. We will do this using Terraform and Docker containers.


I have previously explained how to get setup and running with Terraform, Github Workflows and Azure. We will be building on top of that post and ideas.

The first thing you will need is an Azure zone and A Record entry:

resource "azurerm_dns_zone" "mydomain" {
name = ""
resource_group_name =

resource "azurerm_dns_a_record" "home-server" {
name = "home-server"
zone_name =
resource_group_name =
ttl = 300
records = [""] # Updated by script

The IPv4 address will be updated in a script below. If you want to use IPv6, you will need an aaaa record as well.


We now need a script which will run on a host within our home network to get our IP address and update the a record above. We will be using the azure cli to update the record.

set -ex

az login --service-principal -u ${AZURE_CLIENT_ID} -p ${AZURE_CLIENT_SECRET} --tenant ${AZURE_TENANT_ID}

newIp="$(dig +short"
oldIp="$(az network dns record-set a show --resource-group ${AZURE_RESOURCE_GROUP} --zone-name ${AZURE_ZONE_NAME} --name ${AZURE_RECORD_NAME} -o tsv --query "aRecords[0].ipv4Address")"

if [[ "$newIp" == "$oldIp" ]]; then
echo "IP has not been updated"
echo "Updating IP to ${newIp}"
az network dns record-set a remove-record --resource-group ${AZURE_RESOURCE_GROUP} --zone-name ${AZURE_ZONE_NAME} --record-set-name ${AZURE_RECORD_NAME} --ipv4-address ${oldIp} --keep-empty-record-set
az network dns record-set a add-record --resource-group ${AZURE_RESOURCE_GROUP} --zone-name ${AZURE_ZONE_NAME} --record-set-name ${AZURE_RECORD_NAME} --ipv4-address ${newIp}

There are some environment variables above which we will be injecting to the docker container below.


First we will want a Dockerfile which wraps up the shell script:


# To get the `dig` unix command
RUN apk add --no-cache bind-tools



We can then build and run this dockerfile:

docker build -t azddns .
docker run --rm \
-e AZURE_CLIENT_ID=<insert client id> \
-e AZURE_CLIENT_SECRET=<insert client secret> \
-e AZURE_TENANT_ID=<insert tenant id> \
-e AZURE_RESOURCE_GROUP=resource-group \
-e \
-e AZURE_RECORD_NAME=home-server \

Running this docker run command should be done on a regular basis. This could be done with a cron job, or by using ofelia.

Here is the docker-compose entry:

build: azddns
container_name: azddns
AZURE_RESOURCE_GROUP: "resource-group"
AZURE_RECORD_NAME: "home-server"

And the entry in the ofelia config:

[job-exec "az ddns"]
schedule = @hourly
container = azddns
command = /


And that's it! You could obviously alter this to use other cloud providers as well, but you now control one more aspect of your tech stack.