Part 7: Resolve Names with Azure DNS

Configure Azure Private DNS to resolve VM names across peered virtual networks.

Introduction

30 Second Summary

A string of numbers is easy to forget when several machines look almost identical. A clear name gives each machine an address people can remember.

In this project, you will build private hostname resolution across two peered Azure Virtual Networks with Azure Private DNS. You will turn a failed lookup from vm-1 into a working connection to vm-spoke.nextwork.internal.

What You'll Build

By the end, you'll see vm-1 resolve vm-spoke.nextwork.internal to 10.30.1.4 across the peered networks.

By the end of this project, you'll have:

  • A working cross-VNet hostname that returns replies from vm-spoke when used on vm-1.
  • An automatically registered A record for vm-spoke.nextwork.internal visible in nextwork.internal.
  • A routing-versus-DNS demonstration that explains why one VNet registers records while another only resolves them.
  • Secret Mission: Add a manual application alias at app.nextwork.internal for a resource outside VM autoregistration.

Are there any prerequisites?

You need an Azure subscription with permission to deploy networking, compute, NAT Gateway, public IP, and Private DNS resources. No local development tools are required.

Before We Start

This checkpoint commits you to the private naming layer you are about to build through Azure portal plus Azure Linux VM Run Command. The plan has vm-1 query vm-spoke through the stable hostname vm-spoke.nextwork.internal instead of relying on 10.30.1.4.

Restore the Two-VNet Lab

Private hostname testing needs two running virtual networks with traffic flowing between them. The previous lab was deleted, so its prerequisite topology needs to be restored before you add Private DNS.

An Azure Resource Manager template restores the complete lab through the Azure portal in one deployment. This keeps the step focused on rebuilding the foundation instead of repeating every networking task from earlier projects.

In this step, get ready to:
  • Load the complete ARM template into the Azure portal.
  • Deploy the two virtual networks with their VMs and supporting network resources.
  • Verify the VMs, reciprocal peerings, and Run Command access.
Load the ARM template

The template declares the complete prerequisite environment as one deployment. Keeping it unchanged ensures every resource name and private IP matches the DNS exercises ahead.

  • Sign in to the Azure portal with the account that has permission to deploy networking and compute resources.
  • Confirm the portal shows the Azure subscription you intend to use for this lab.
  • Search for Deploy a custom template.
  • Select Build your own template in the editor.
  • Remove the blank template from the editor.
  • Use the second tab below to copy the complete azuredeploy.json template into the editor.

Tab 1

Great. Keep the template unchanged so the deployed resources match the rest of the project.

Tab 2

  • Copy Part 1 into the blank Azure template editor.
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for all regional resources."
      }
    },
    "adminUsername": {
      "type": "string",
      "defaultValue": "azureuser",
      "metadata": {
        "description": "Administrator username for both Linux VMs."
      }
    },
    "adminPassword": {
      "type": "securestring",
      "minLength": 12,
      "maxLength": 72,
      "metadata": {
        "description": "Administrator password for both Linux VMs."
      }
    },
    "vmSize": {
      "type": "string",
      "defaultValue": "Standard_B2ms",
      "allowedValues": [
        "Standard_B2ms"
      ],
      "metadata": {
        "description": "VM size for both Linux VMs."
      }
    }
  },
  "variables": {
    "sourceVnetName": "vnet-nextwork-lab",
    "sourceSubnetName": "subnet-nextwork",
    "spokeVnetName": "vnet-nextwork-spoke",
    "spokeSubnetName": "subnet-spoke",
    "natPublicIpName": "pip-nextwork-nat",
    "natGatewayName": "nat-nextwork-lab",
    "sourceNicName": "nic-vm-1",
    "spokeNicName": "nic-vm-spoke",
    "sourceVmName": "vm-1",
    "spokeVmName": "vm-spoke",
    "sourcePeeringName": "peering-lab-to-spoke",
    "spokePeeringName": "peering-spoke-to-lab"
  },
  "resources": [
    {
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2024-01-01",
      "name": "[variables('natPublicIpName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard",
        "tier": "Regional"
      },
      "properties": {
        "publicIPAllocationMethod": "Static",
        "publicIPAddressVersion": "IPv4",
        "idleTimeoutInMinutes": 4
      }
    },
    {
      "type": "Microsoft.Network/natGateways",
      "apiVersion": "2024-01-01",
      "name": "[variables('natGatewayName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard"
      },
      "properties": {
        "idleTimeoutInMinutes": 4,
        "publicIpAddresses": [
          {
            "id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('natPublicIpName'))]"
          }
        ]
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/publicIPAddresses', variables('natPublicIpName'))]"
      ]
    },
    {
      "type": "Microsoft.Network/virtualNetworks",
      "apiVersion": "2024-01-01",
      "name": "[variables('sourceVnetName')]",
      "location": "[parameters('location')]",
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "10.20.0.0/16"
          ]
        },
        "subnets": [
          {
            "name": "[variables('sourceSubnetName')]",
            "properties": {
              "addressPrefix": "10.20.1.0/24",
              "natGateway": {
                "id": "[resourceId('Microsoft.Network/natGateways', variables('natGatewayName'))]"
              }
            }
          }
        ]
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/natGateways', variables('natGatewayName'))]"
      ]
    },
    {
      "type": "Microsoft.Network/virtualNetworks",
      "apiVersion": "2024-01-01",
      "name": "[variables('spokeVnetName')]",
      "location": "[parameters('location')]",
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "10.30.0.0/16"
          ]
        },
        "subnets": [
          {
            "name": "[variables('spokeSubnetName')]",
            "properties": {
              "addressPrefix": "10.30.1.0/24"
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings",
      "apiVersion": "2024-01-01",
      "name": "[format('{0}/{1}', variables('sourceVnetName'), variables('sourcePeeringName'))]",
      "properties": {
        "allowVirtualNetworkAccess": true,
        "allowForwardedTraffic": false,
        "allowGatewayTransit": false,
        "useRemoteGateways": false,
        "remoteVirtualNetwork": {
          "id": "[resourceId('Microsoft.Network/virtualNetworks', variables('spokeVnetName'))]"
        }
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/virtualNetworks', variables('sourceVnetName'))]",
        "[resourceId('Microsoft.Network/virtualNetworks', variables('spokeVnetName'))]"
      ]
    },
    {
      "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings",
      "apiVersion": "2024-01-01",
      "name": "[format('{0}/{1}', variables('spokeVnetName'), variables('spokePeeringName'))]",
      "properties": {
        "allowVirtualNetworkAccess": true,
        "allowForwardedTraffic": false,
        "allowGatewayTransit": false,
        "useRemoteGateways": false,
        "remoteVirtualNetwork": {
          "id": "[resourceId('Microsoft.Network/virtualNetworks', variables('sourceVnetName'))]"
        }
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/virtualNetworks', variables('sourceVnetName'))]",
        "[resourceId('Microsoft.Network/virtualNetworks', variables('spokeVnetName'))]"
      ]
    },
  • Paste Part 2 immediately after Part 1 in the same editor.
    {
      "type": "Microsoft.Network/networkInterfaces",
      "apiVersion": "2024-01-01",
      "name": "[variables('sourceNicName')]",
      "location": "[parameters('location')]",
      "properties": {
        "enableAcceleratedNetworking": false,
        "enableIPForwarding": false,
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "primary": true,
              "privateIPAddress": "10.20.1.4",
              "privateIPAddressVersion": "IPv4",
              "privateIPAllocationMethod": "Static",
              "subnet": {
                "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('sourceVnetName'), variables('sourceSubnetName'))]"
              }
            }
          }
        ]
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/virtualNetworks', variables('sourceVnetName'))]"
      ]
    },
    {
      "type": "Microsoft.Network/networkInterfaces",
      "apiVersion": "2024-01-01",
      "name": "[variables('spokeNicName')]",
      "location": "[parameters('location')]",
      "properties": {
        "enableAcceleratedNetworking": false,
        "enableIPForwarding": false,
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "primary": true,
              "privateIPAddress": "10.30.1.4",
              "privateIPAddressVersion": "IPv4",
              "privateIPAllocationMethod": "Static",
              "subnet": {
                "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('spokeVnetName'), variables('spokeSubnetName'))]"
              }
            }
          }
        ]
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/virtualNetworks', variables('spokeVnetName'))]"
      ]
    },
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2023-09-01",
      "name": "[variables('sourceVmName')]",
      "location": "[parameters('location')]",
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "computerName": "[variables('sourceVmName')]",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPassword')]",
          "linuxConfiguration": {
            "disablePasswordAuthentication": false,
            "provisionVMAgent": true
          }
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "Canonical",
            "offer": "0001-com-ubuntu-server-jammy",
            "sku": "22_04-lts-gen2",
            "version": "latest"
          },
          "osDisk": {
            "name": "[format('{0}-osdisk', variables('sourceVmName'))]",
            "caching": "ReadWrite",
            "createOption": "FromImage",
            "deleteOption": "Delete",
            "managedDisk": {
              "storageAccountType": "Standard_LRS"
            }
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('sourceNicName'))]",
              "properties": {
                "primary": true,
                "deleteOption": "Delete"
              }
            }
          ]
        },
        "diagnosticsProfile": {
          "bootDiagnostics": {
            "enabled": false
          }
        }
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/networkInterfaces', variables('sourceNicName'))]"
      ]
    },
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2023-09-01",
      "name": "[variables('spokeVmName')]",
      "location": "[parameters('location')]",
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "computerName": "[variables('spokeVmName')]",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPassword')]",
          "linuxConfiguration": {
            "disablePasswordAuthentication": false,
            "provisionVMAgent": true
          }
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "Canonical",
            "offer": "0001-com-ubuntu-server-jammy",
            "sku": "22_04-lts-gen2",
            "version": "latest"
          },
          "osDisk": {
            "name": "[format('{0}-osdisk', variables('spokeVmName'))]",
            "caching": "ReadWrite",
            "createOption": "FromImage",
            "deleteOption": "Delete",
            "managedDisk": {
              "storageAccountType": "Standard_LRS"
            }
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('spokeNicName'))]",
              "properties": {
                "primary": true,
                "deleteOption": "Delete"
              }
            }
          ]
        },
        "diagnosticsProfile": {
          "bootDiagnostics": {
            "enabled": false
          }
        }
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/networkInterfaces', variables('spokeNicName'))]"
      ]
    }
  ],
  "outputs": {
    "sourceVmPrivateIp": {
      "type": "string",
      "value": "10.20.1.4"
    },
    "spokeVmPrivateIp": {
      "type": "string",
      "value": "10.30.1.4"
    },
    "sourceVmName": {
      "type": "string",
      "value": "[variables('sourceVmName')]"
    },
    "spokeVmName": {
      "type": "string",
      "value": "[variables('spokeVmName')]"
    }
  }
}

What does this template create?

  • The source network uses vnet-nextwork-lab with the 10.20.0.0/16 address space.
  • The spoke network uses vnet-nextwork-spoke with the 10.30.0.0/16 address space.
  • Reciprocal peerings carry private traffic between the two networks.
  • A NAT Gateway gives the source subnet outbound connectivity for Run Command.
  • Two Ubuntu Server 22.04 LTS VMs provide the source and target machines for the DNS tests.
  • Select Save in the template editor.

The portal checks the JSON before opening the deployment form. You should see fields for the resource group and the four template parameters.

Template validation not completing?

  • Confirm the first character in the editor is {.
  • Confirm the final character is }.
  • Replace the editor contents with the complete template again if part of the JSON was missed.
  • Still stuck? Help me diagnose why this ARM template is not passing validation in the Azure portal.
Configure and deploy the lab

The deployment form supplies values to the template parameters. The resource group and region determine where Azure creates the lab.

  • Set Resource group to NextWork-Networking.
  • Set Region to Central US.

The template creates two Standard_B2ms VMs with two vCPUs and 8 GiB of memory each. Your subscription needs at least four available Standard BS Family vCPUs in the deployment region.

  • Keep Vm Size set to Standard_B2ms.
  • Enter azureuser in Admin Username.

Creating these resources starts usage-based Azure charges. The cleanup section removes the complete lab when you finish.

  • Enter a new complex password in Admin Password.
  • Select Review + create.

Azure now validates the template and parameter values. Use the matching outcome below when validation finishes.

✔️ Validation passed

  • Select Create to start the deployment.

Provisioning both VMs often takes several minutes, so leave the deployment page open. Azure creates the network resources before it starts the VMs.

You should see confirmation that the deployment succeeded.

ⓧ The default VM size is unavailable

A zero Standard BS Family vCPU quota blocks every Standard_B2ms deployment in that region. The ARM template cannot override this subscription limit, so request enough quota or use a region with available BS Family quota before retrying.

  • Open Quotas from the Azure portal search.
  • Select Compute on the overview page.
  • Filter Region to the region used by this deployment.
  • Select Standard BS Family vCPUs.
  • Select New Quota Request.
  • Select Enter a new limit.
  • Enter 4 as the new limit.
  • Select Submit to start Azure's quota review.

Repeat the deployment after validation passes. You should see confirmation that the deployment succeeded.

Deployment failed?

  • Open the failed deployment operation to identify the resource that Azure could not create.
  • Confirm your subscription permits virtual machines, public IP addresses, NAT Gateway resources, and virtual networks in the selected region.
  • Check that the deployment region has at least four available Standard BS Family vCPUs.
  • Request a Standard BS Family quota increase or choose another region with available BS Family quota when Azure reports a quota limit.
  • Confirm both enableAcceleratedNetworking values are false when Azure reports that the NIC configuration is incompatible with Standard_B2ms.
  • Still stuck? Help me diagnose this Azure ARM deployment failure without asking for my administrator password.
Verify the restored topology

A successful deployment confirms that Azure accepted the template. The resource states now prove that both VMs and the routes between them are ready for the DNS work.

  • Open NextWork-Networking from the deployment result.
  • Select vm-1 from the resource group.
  • Confirm its status is Running.
  • Confirm its private IP address is 10.20.1.4.
  • Return to NextWork-Networking.
  • Select vm-spoke from the resource group.
  • Confirm its status is Running.
  • Confirm its private IP address is 10.30.1.4.

Both VMs are running with the fixed private addresses used throughout the project. That gives the DNS tests a stable source and target.

  • Return to NextWork-Networking.
  • Select vnet-nextwork-lab.
  • Open the virtual network's peering list.
  • Confirm peering-lab-to-spoke is Connected.
  • Return to NextWork-Networking.
  • Select vnet-nextwork-spoke.
  • Open the virtual network's peering list.
  • Confirm peering-spoke-to-lab is Connected.

What do the two peerings prove?

Each peering represents one direction of the relationship between the virtual networks. A Connected state in both directions confirms that the private routing foundation is ready.

  • Return to NextWork-Networking.
  • Select vm-1.
  • Select Run command under Operations.
  • Choose ifconfig from the built-in commands.

Before you run it, which network interface details do you expect vm-1 to report?

  • Select Run.

You should see network interface output from vm-1, including its private address 10.20.1.4.

That is the foundation restored. The source VM is running, its outbound path supports Run Command, and both peering directions are connected.

Run Command not returning output?

  • Confirm vm-1 still shows the Running status.
  • Confirm subnet-nextwork is associated with nat-nextwork-lab.
  • Allow the VM outbound connectivity on port 443 so Run Command can return its result.
  • Still stuck? Help me diagnose why Azure Linux VM Run Command is not returning ifconfig output from vm-1.

Your two-VNet lab is ready again. Next, you'll give the spoke VM a private hostname that Azure manages automatically.

Register vm-spoke in Private DNS

Your restored lab now has two running VMs connected through Azure Virtual Network peering. Applications need a stable private name for the spoke VM instead of depending on its private IP address.

Azure Private DNS manages custom private domain names for linked virtual networks. This step turns vnet-nextwork-spoke into a registration network for nextwork.internal.

In this step, get ready to:
  • Create the private DNS zone for your internal hostnames.
  • Link the spoke VNet with VM autoregistration enabled.
  • Confirm that Azure registered the spoke VM automatically.
Create the private DNS zone

A private DNS zone holds internal hostname records that linked virtual networks can resolve. You will create nextwork.internal inside the resource group from the restored lab.

  • Select the search bar at the top of the Azure portal from earlier.
  • Enter private dns zones.
  • Select Private DNS zone under Marketplace.
  • Select NextWork-Networking in the Resource group field.
  • Enter nextwork.internal in the Name field.
  • Select Review + Create.
  • Select Create after validation succeeds.

Good progress. nextwork.internal now gives the lab a private namespace for its internal hostnames.

Why Azure Private DNS?

Azure Private DNS provides managed private naming for linked virtual networks. It keeps this lab focused on registration and resolution without requiring a custom DNS server.

Link the spoke VNet

A virtual network link determines which VNet can use the zone. Autoregistration makes vnet-nextwork-spoke a registration network that contributes VM records.

  • On nextwork.internal, select Virtual Network Links under DNS Management.
  • Select + Add.
  • Enter link-vnet-nextwork-spoke in the Link name field.
  • Confirm the intended subscription in the Subscription field.
  • Select vnet-nextwork-spoke in the Virtual Network field.
  • Select Enable auto registration.
  • Select Create.
  • Wait for link-vnet-nextwork-spoke to appear with Link Status set to Completed.

That is the registration relationship in place. Azure can now register the existing spoke VM in the zone.

Link Not Reaching Completed?

  • Check that the link targets vnet-nextwork-spoke.
  • Check that Enable auto registration is selected for the link.

Still stuck? Help me troubleshoot the private DNS link.

Verify the auto-registered record

An A record maps a hostname to an IPv4 address. Azure should create this mapping from the primary network interface on vm-spoke.

Before you check the record, consider which private IP Azure should associate with vm-spoke.

  • On nextwork.internal, select Recordsets under DNS Management.
  • Locate the record named vm-spoke.
  • Confirm its Type is A.
  • Confirm that the record points to 10.30.1.4.
  • Confirm Auto registered is True.

You will see an automatically registered vm-spoke A record pointing to 10.30.1.4. This gives the VM the fully qualified domain name vm-spoke.nextwork.internal.

What Does Auto Registered Mean?

The True value shows that Azure created the record through VM autoregistration. Azure maintains the record as part of the spoke VM's lifecycle.

Your spoke VM now has a managed private hostname. Next, you will test whether network peering alone lets vm-1 resolve that name.

Prove Peering Is Not DNS

Your spoke VM now has an automatically registered name in Azure Private DNS. The next question is whether vm-1 can use that name from the other virtual network.

VNet peering carries packets between the virtual networks. In this step, Azure Linux VM Run Command checks the IP path separately from the hostname lookup.

In this step, get ready to:
  • Run an IP connectivity test from vm-1.
  • Run a hostname lookup from the same VM.
  • Interpret the contrast between routing and DNS.
Separate routing from name resolution

A private IP test asks whether packets can reach a specific network interface. A fully qualified domain name lookup asks whether DNS can translate a stable name into that address.

  • Use the Azure portal search bar to open vm-1.
  • Select Run command under Operations.
  • Select RunShellScript.
Run the paired test from vm-1

One script keeps the source consistent for both tests. That makes the result a clean comparison.

  • Paste the following commands into the command editor:
ping -c 4 10.30.1.4
getent hosts vm-spoke.nextwork.internal

What Do These Commands Test?

  • The first line uses ping with -c 4 to send four echo requests to 10.30.1.4.
  • The second line uses getent to query Ubuntu's host database for vm-spoke.nextwork.internal.
  • Together, the lines compare private IP reachability with hostname lookup from the same VM.

Before you run the script, make a quick prediction about whether both tests will succeed because the VNets are peered.

  • Select Run to execute the script.

You'll see replies from 10.30.1.4. This proves the reciprocal VNet peering carries traffic from vm-1 to vm-spoke.

The getent line returns no address for vm-spoke.nextwork.internal. Run Command reports the lookup as failed because vnet-nextwork-lab has no virtual network link to nextwork.internal.

That split is the key result. You have isolated the unresolved naming layer while keeping the working network path visible.

Not Seeing the Expected Split?

  • Confirm both VMs show Running if the IP test has no replies.
  • Confirm both reciprocal peerings show Connected if the IP test has no replies.
  • Confirm link-vnet-nextwork-spoke is the only virtual network link if the hostname unexpectedly resolves.

Still stuck? Help me diagnose this RunShellScript result.

The network path is healthy. Next, you'll give vm-1 access to the private zone so the hostname can resolve across the peering.

Link the Source VNet and Resolve the Name

The last test proved that vm-1 can send packets to 10.30.1.4 across VNet peering. Its failed hostname lookup also exposed the missing DNS relationship.

In this step, you'll make vnet-nextwork-lab a resolution-only network for Azure Private DNS. The spoke VNet keeps its role as the registration network.

In this step, get ready to:
  • Link the source VNet to nextwork.internal without automatic registration.
  • Confirm that the new link reaches its completed state.
  • Resolve and reach vm-spoke.nextwork.internal from vm-1.
Link the source VNet to the zone

A VNet link without automatic registration lets its VMs query records from the private zone. It does not create records for those VMs.

  • Return to the nextwork.internal private DNS zone from earlier.
  • Under DNS Management, select Virtual Network Links.
  • Select + Add.
  • Enter link-vnet-nextwork-lab in Link name.
  • Select vnet-nextwork-lab under Virtual Network.
  • Confirm that Enable auto registration remains clear.
  • Select Create.
Confirm the link is ready

The new link can take a few moments to become operational. A short wait here is normal while Azure connects the VNet to the zone.

  • Wait for link-vnet-nextwork-lab to appear in Virtual Network Links.
  • Confirm that its Link Status shows Completed.

You now have two completed links with different jobs. Together, they let one VNet publish the hostname while the other VNet resolves it.

How Do the Two Links Divide the Work?

  • link-vnet-nextwork-spoke is the registration link. Automatic registration creates and maintains the vm-spoke.nextwork.internal record.
  • link-vnet-nextwork-lab is the resolution link. It lets vm-1 query that record without registering vm-1 in the zone.
Resolve and reach the hostname

The earlier failed lookup can remain in the local DNS cache after the link starts working. Clearing the cache makes the next lookup test the completed relationship.

  • Return to vm-1 in NextWork-Networking.
  • Under Operations, select Run command.
  • Select RunShellScript.

Before you run this check, predict whether the hostname fails again or resolves to a private address.

  • Clear the resolver cache and retest the hostname by running this script:
resolvectl flush-caches
getent hosts vm-spoke.nextwork.internal
ping -c 4 vm-spoke.nextwork.internal

What Does This Check Prove?

  • resolvectl flush-caches removes the earlier failed lookup from the local resolver cache.
  • getent hosts vm-spoke.nextwork.internal checks whether the hostname now maps to a private address.
  • ping -c 4 vm-spoke.nextwork.internal uses that hostname to send four echo requests across the existing peering.
  • Review the hostname lookup for the resolved private IP address.
  • Confirm that the hostname ping receives replies from 10.30.1.4.

You'll see 10.30.1.4 beside vm-spoke.nextwork.internal. The hostname ping returns replies from the same private address.

You have closed the missing DNS relationship. vm-1 can now discover and reach vm-spoke by its stable private hostname.

Hostname Still Not Resolving?

  • Confirm that link-vnet-nextwork-lab targets vnet-nextwork-lab in the zone's Virtual Network Links list.
  • Wait until Link Status shows Completed before rerunning the script.
  • Rerun all three commands in the same RunShellScript request so the cache is cleared before the lookup.

Still stuck? Help me troubleshoot private hostname resolution from vm-1.

Secret mission

Add an Application Alias

Autoregistration already manages the VM hostname. In this mission, you'll create app.nextwork.internal manually. Then you'll prove that vm-1 can resolve it.

Clean Up Your Resources

Clean Up Your Resources

Your Azure lab contains resources that can continue to incur usage-based charges. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Cost warning

Azure DNS billing is based on hosted DNS zones and DNS queries.

The VMs plus managed disks have separate usage-based charges.

Azure NAT Gateway, public IP address, and peering traffic can also incur charges.

  • Choose Pause if you want to keep the lab for later.
  • Choose Delete if you have finished the lab.

Resources you used:

  • The NextWork-Networking resource group.
  • The vnet-nextwork-lab virtual network with its subnet-nextwork subnet.
  • The vnet-nextwork-spoke virtual network with its subnet-spoke subnet.
  • The two reciprocal Azure Virtual Network peering resources.
  • The nic-vm-1 network interface at 10.20.1.4.
  • The nic-vm-spoke network interface at 10.30.1.4.
  • The vm-1 virtual machine.
  • The vm-spoke virtual machine.
  • The managed OS disk attached to vm-1.
  • The managed OS disk attached to vm-spoke.
  • The Azure NAT Gateway named nat-nextwork-lab.
  • The public IP address named pip-nextwork-nat.
  • The Azure Private DNS zone named nextwork.internal.
  • The registration link named link-vnet-nextwork-spoke.
  • The resolution-only link named link-vnet-nextwork-lab.
  • The auto-registered A record named vm-spoke.nextwork.internal.
  • The manually created A record named app.nextwork.internal.

Keep everything running

No action needed. Choose this if you want to repeat the private hostname tests or continue into another networking project.

  • The vm-1 VM remains available for Run Command tests.
  • The vm-spoke.nextwork.internal hostname remains auto-registered at 10.30.1.4.
  • The manual app.nextwork.internal alias remains available at 10.30.1.4.
  • Running resources plus persistent resources can continue to incur charges.

Pause - I'll come back to this later

Shut down both running VMs to stop their compute charges. Your networking resources plus DNS configuration remain available for later.

  • Return to the NextWork-Networking resource group in the Azure portal.
  • Open vm-1 from the resource list.
  • Select Stop to deallocate vm-1.
  • Return to the NextWork-Networking resource group.
  • Open vm-spoke from the resource list.
  • Select Stop to deallocate vm-spoke.
  • Return to the resource group to confirm both VMs show a deallocated state.

What stays after pausing?

Deallocating both VMs stops their compute charges. Managed disks plus persistent networking resources can continue to incur charges.

The auto-registered vm-spoke.nextwork.internal record is removed when vm-spoke is deallocated. The manual app.nextwork.internal record remains in the zone.

Delete - I don't want to use this again

Deleting this resource group is permanent. It removes every lab resource listed above.

  • Return to the NextWork-Networking resource group in the Azure portal.
  • Select Delete resource group.
  • Enter NextWork-Networking when prompted.
  • Confirm the deletion.
  • Return to the resource group list after Azure finishes the deletion.

You should no longer see NextWork-Networking in the resource group list. That confirms the VMs, networking resources, Private DNS zone, links, and records have been removed.

Nice Work!

Nice Work!

Excellent work. You built a private naming layer across two peered Azure virtual networks with Azure Private DNS.

You've learned how to:

  • Restore a two-VNet Azure lab from azuredeploy.json. Confirm both virtual machines through Azure Linux VM Run Command.
  • Create an Azure Private DNS zone that automatically registers vm-spoke.nextwork.internal as an A record. Use a registration network to tie that record to the VM lifecycle.
  • Prove that Virtual Network peering carries traffic without providing private name resolution. Add a resolution-only network so vm-1 can resolve and reach vm-spoke.nextwork.internal by FQDN.
  • Complete the optional Secret Mission by creating app.nextwork.internal as a manual A record. Confirm that it resolves to 10.30.1.4 outside VM primary-NIC autoregistration.

Ready to quiz yourself?