Creating a Dynamic DNS service to host your website in your home lab.
This article covers how to create and set up your own Dynamic DNS service so that you can host your web site in your home lab.
Before we begin, lets set the context and discuss the environment we will be working with.
The Goal: I have a domain name registered through square space but do not have a website built or hosted on square space. Hosting at square is a bit expensive, their web design templates are great, but I would like to build one myself. Should be a good exercise in learning scripting, azure services, DNS and possibly java script if I end up building my own web site.
The Environment: we are starting with a domain that is registered at Square space, but the DNS and email are tied to my O365 subscription since I used that domain (kodakcafe.com) to register email services via O365.
The challenge: I do not have a static public IP at home (just like most of us), hosting a web site in my home lab would not work well with a Dynamic public IP. This leads me to needing some form of Dynamic DNS service and that can get expensive. So, I decided to build my own Dynamic DNS service. But this cannot be accomplished via O365 where I currently have my DNS managed for my domain since O365 does not offer any API’s that I can use to dynamically update my ever-changing public IP for my home internet.
The solution: move my DNS functions from O365 to Azure and hopefully that will give me API access to the DNS service that I can write a script that runs in my home lab that will update the Azure DNS with my current public IP address at regular intervals so it acts like a Dynamic DNS service.
How it was done.
Go to
Click on create resource
Search and find DNS zone
Click on Microsoft DNS Zone as shown below
Click on create
Click on the create new link to create a new Resource group for the DNS service
Create a new resource group and give it a meaningful name
You do not need to check the box for child of existing zone (this is when you have a sub domain such as lab.kodakcafe.com
Complete the form as shown below
Click review + create
Wait for validation to complete
Now click on create
Once deployment is complete you should see the status as shown below
Now click on go to resource
Since O365 is currently managing the DNS for my domain for the purpose of email services, we first need to set up azure DNS to handle email services so that Azure can then redirect to O365 for email services. The intent here is to let O365 be the email service venue and Azure be the primary DNS that will redirect traffic based on the service required (i.e. email, go to o365, web traffic go to my home lab)
To begin lets click on Record Sets
By default you will see the following
Click on the add button
Create the MX record for mail exchange as shown below for
kodakcafe-com.mail.protection.outlook.com
Click add
Next, we need a SPF record for outbound emails
Complete the data as shown above and click add
Next we need to add a CNAME for auto discovery so that mobile devices, outlook apps etc can auto discover our mail exchange service
Now click add
So now we have mirrored the DNS record handled by O365 on Azure and Azure is ready to replace O365 for DNS as shown below
At this point, we just need to update Square space to make sure that DNS for kodakcafe.com is now handled by Azure and not O365.
Here is what square space looks like before we update
We created the above services in Azure
Below we see square space using O365 for DNS services, we will need to update these.
Click on the update name servers link
We now update the records with the following Azure addresses
ns1-09.azure-dns.com
ns2-09.azure-dns.net
ns3-09.azure-dns.org
ns4-09.azure-dns.info
Click save
Our change will now start propagating
To verify open up a terminal and run nslookup -type=ns kodakcafe.com
You should see azure listed as the DNS server.
@mac ~ % nslookup -type=ns kodakcafe.com
Non-authoritative answer:
kodakcafe.com nameserver = ns4-09.azure-dns.info.
kodakcafe.com nameserver = ns1-09.azure-dns.com.
kodakcafe.com nameserver = ns3-09.azure-dns.org.
kodakcafe.com nameserver = ns2-09.azure-dns.net.
we can also verify that our mail service is being redirected to O365 by azure and is working properly by running the command below
nslookup -type=mx kodakcafe.com
the expected output is
Non-authoritative answer:
kodakcafe.com mail exchanger = 0 kodakcafe-com.mail.protection.outlook.com.
The next step is to start working on the DDNS.
First we will start with creating an A record for , this will be our record for the Website
Lets hop back over to Azure DNS and add another record.
For now we will use 1.1.1.1. this is just a place holder. When we build out our DDNS script, that script will update this record every 10 minutes or so with the real public ip address of our home internet.
At this point we should have the following set up
Before we begin writing our script for DDNS. The following need to be set up in Azure
From the Azure portal home click on Entra ID
Select app registrations
Click new registration
Fill out the form as shown below and click register
Document the client and tenant ID
Client ID: f9b4570b-d23f-444b-8153-250368d637e2
Tenant ID: 4da97921-dadc-49d7-b03e-18d6cc034904
Click on the add a certificate or secret link
Click on new client secret
Client Secret : _.h8Q~KC6GsyIivleJX5NgEc3mVmgHsMvb5eXbfy
Document the client secret value
Let’s go back to our DNS service. Go to the azure home >> click on the resource group dor our DNS rg-dns-kodakcafe and click on the DNS resource as shown below
Now click on IAM
Click on add role assignments
Find “DNS Zone Contributor” and click next
Click select member
Now search for your DDNS resource sp-ddns-kodakcafe
Select the application
The review and assign.
What we are trying to accomplish is the following
You should now see the following
The big picture is the following
Create your powershell script, the code is below
$ErrorActionPreference = "Stop"
# ================= CONFIG =================
$TenantId = "yourtenantidhere"
$ClientId = "yourclientidhere"
$ClientSecret = "yourclientsecrethere"
$SubscriptionId = "yoursubscriptionidhere"
$ResourceGroup = "rg-dns-kodakcafe"
$ZoneName = "kodakcafe.com"
$RecordName = "home"
$Ttl = 300
# ==========================================
$LogDir = "C:\Scripts\DDNS\Logs"
New-Item -ItemType Directory -Path $LogDir -Force | Out-Null
$LogFile = Join-Path $LogDir ("ddns-" + (Get-Date -Format "yyyyMMdd") + ".log")
function Log($msg) {
Add-Content -Path $LogFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') $msg"
}
function Get-PublicIP {
Invoke-RestMethod "https://api.ipify.org"
}
function Get-Token {
$body = @{
grant_type = "client_credentials"
client_id = $ClientId
client_secret = $ClientSecret
resource = "https://management.azure.com/"
}
(Invoke-RestMethod `
-Method POST `
-Uri "https://login.microsoftonline.com/$TenantId/oauth2/token" `
-Body $body `
-ContentType "application/x-www-form-urlencoded"
).access_token
}
# Detect current public IP
$ip = (Get-PublicIP).ToString().Trim()
Log "Detected public IP: $ip"
# Authenticate to Azure
$token = Get-Token
# Azure DNS REST endpoint
$uri = "https://management.azure.com/subscriptions/${SubscriptionId}/resourceGroups/${ResourceGroup}/providers/Microsoft.Network/dnsZones/${ZoneName}/A/${RecordName}?api-version=2018-05-01"
$headers = @{ Authorization = "Bearer $token" }
# Get current DNS record
$current = Invoke-RestMethod -Method GET -Uri $uri -Headers $headers
# Extract current DNS IP
$currentIp = $null
if ($current.properties.ARecords.Count -gt 0) {
$currentIp = $current.properties.ARecords[0].ipv4Address
}
Log "Current DNS IP: $currentIp"
# Exit if no update is needed
if ($currentIp -eq $ip) {
Log "No update required."
exit 0
}
# Build update payload
$payload = @{
properties = @{
TTL = 300
ARecords = @(
@{ ipv4Address = $ip }
)
}
} | ConvertTo-Json -Depth 5
# Update DNS record
Invoke-RestMethod `
-Method PUT `
-Uri $uri `
-Headers $headers `
-Body $payload `
-ContentType "application/json"
Log "DNS updated from $currentIp to $ip"
Write-Host "DNS updated from $currentIp to $ip"
Log into your home lab server and open up Powershell (run as administrator)
Now run the command
powershell.exe -ExecutionPolicy Bypass -File C:\ddns\ddnsupdate.ps1
now open up and note down your public address
then run nslookup from terminal and the IP address should be the same.
What we just confirmed is that our powershell script is successfully updating Azure DNS service via the API call.
Next step is to use Task scheduler to run this every 15 minutes.
Open task scheduler on your server
Right click and select create task (do not use Create Basic Task)
Now configure the scheduled task as follows
On the trigger tab, add new trigger as shown below
On the actions tab add a new action as shown below
Program/Script = powershell.exe
Arguments = -NoProfile -ExecutionPolicy Bypass -File "C:\ddns\ddnsupdate.ps1"
Start in = C:\ddns
How save the schedule task.
You should now see the scheduled task.
Test this by right clicking on the task and selecting the task and click on run
You should see operation completed successfully