Skip to content

Deploy from the Azure Marketplace

Hayami DTM is delivered exclusively through the Azure Marketplace and runs inside your own subscription. Deployment provisions a small cluster of Linux VMs in a VNet you choose; DNS queries and answers never leave your environment.

This page covers the deployment at an operator level. The Marketplace offer walks you through the parameters; the notes below explain what each one is for and how to confirm the result.

  • An Azure subscription and a target resource group, with enough rights to both create resources and assign roles there. See Deployment permissions below; this is the most common reason a first deploy fails.
  • A VNet for the DTM nodes and a free address range: the deployment creates a small dedicated subnet in that VNet, which your other VNets can reach for DNS.
  • A decision on cluster size. Run two or more nodes for high availability and zero-downtime upgrades. A single node has no failover.
  • A decision on your cluster boundary. Every node in a cluster must be able to route to every other node: replication is peer-to-peer, with no leader and no proxy, so one cluster spans exactly one routable domain (a VNet, peered VNets, or VNets joined by a transit connection such as hub-and-spoke or Virtual WAN). Estates that cannot reach each other need a separate cluster each; a node that cannot reach its peers keeps serving DNS from its own copy while quietly diverging, so this is a plan-it-up-front decision, not a recoverable-later one.

Deploying DTM does two distinct things in your target scope: it creates resources (VMs, a managed identity, a Key Vault, disks, a NIC, and an NSG), and it creates role assignments to grant each node identity the roles it needs (see the rights table below). You need permission for both.

In Azure terms that means Owner, or Contributor plus User Access Administrator, on the target resource group or subscription.

Everything DTM needs lands in one resource group (see the recommended layout):

  • DTM nodes (Linux VMs) running the dtm-server service, joined into one cluster.
  • A dedicated Premium SSD data disk per node, attached automatically and mounted at the database path. See Sizing and storage.
  • A Key Vault, dedicated to the deployment, holding the cluster’s secrets and TLS material.
  • One system-assigned managed identity per node: the node’s own Azure identity, with no secret to store or rotate. Its rights are listed below.
  • A network security group (NSG) that admits the DTM ports from inside your network only. See Network access.
  • Stable private IPs for the nodes, so client DNS settings never need to change across upgrades or node replacements.
  • The role assignments each node identity needs (the table below).

There are no public IPs. DTM runs entirely on private addresses inside your VNet.

What one Marketplace deployment creates: DTM nodes on stable private IPs in a dedicated subnet, each with its own Premium SSD data disk and system-assigned managed identity, a subnet NSG, and a dedicated Key Vault that the primary node publishes the cluster secrets to at first boot and every other node reads them from; a numbered panel details the role assignments and NSG rules matching the numbered markers in the diagram. What one Marketplace deployment creates: DTM nodes on stable private IPs in a dedicated subnet, each with its own Premium SSD data disk and system-assigned managed identity, a subnet NSG, and a dedicated Key Vault that the primary node publishes the cluster secrets to at first boot and every other node reads them from; a numbered panel details the role assignments and NSG rules matching the numbered markers in the diagram.

Each node authenticates to Azure as its own system-assigned managed identity, so there are no credentials stored on disk. The deployment grants that identity exactly the roles the node needs and nothing more:

Role Scope Why the node needs it
Reader The DTM resource group Region discovery: region-aware load balancing enumerates which region each node is in.
Contributor The DTM resource group Lifecycle and stable-IP failover: the cluster can reassign a node’s private IP so DNS endpoints stay stable when a node is replaced.
Key Vault Secrets User The deployment’s Key Vault Every node reads the cluster secrets and TLS material from the vault on boot.
Key Vault Secrets Officer The deployment’s Key Vault The primary node only, so it can publish the secrets it generates on first boot.

The Contributor grant is deliberately scoped to the DTM resource group alone, so the cluster can only ever act on its own resources. That is one reason to give DTM a resource group of its own.

On the Marketplace appliance, the cluster’s shared secrets, the initial administrator password and the cluster encryption key, are generated on the VM at first boot, written to Key Vault, and never exposed in the deployment template or its outputs. The primary node generates them and publishes them to the vault (that is what its Key Vault Secrets Officer grant is for); every other node reads the same values back with its Key Vault Secrets User grant, so the whole cluster shares one set. The management TLS certificate is generated locally on each node at first boot on this path and is not stored in the vault.

The Terraform path handles the administrator password and the cluster encryption key the same way, generating them on the node and into Key Vault so they never land in Terraform state, and additionally has the primary publish a shared UI TLS bundle to the vault (the dtm-tls secret) that the other nodes read, so that path serves one cluster-wide UI certificate. See Terraform provider setup for the details.

For the life of these secrets after day one, see rotating secrets and TLS certificates (the first-boot certificate is valid for two years).

Section titled “Recommended: a dedicated resource group per region”

Give DTM its own, new resource group for each region it runs in, holding all of that region’s DTM resources. It keeps things clean in three ways:

  • Clean lifecycle. DTM’s resources are not tangled up with anything else.
  • Least privilege. The node identity’s Contributor grant only ever covers DTM’s own resources, never your wider estate.
  • Simple teardown. Removing a regional deployment is just deleting its resource group.

For a two-region deployment, that means one dedicated resource group per region. Here is what a two-region deployment looks like:

A two-region deployment, one dedicated resource group per region: rg-ne in northeurope and rg-we in westeurope. Each holds a DTM node on a stable private IP (Standard_D2s_v5), an NSG listing the deploy port table (53 DNS, 853 DoT if enabled, 443 DoH if enabled, 8080 Web UI, 8443 API and management, 7946 replication between nodes only), a Premium SSD data disk (64 GiB P6, grows in place, host caching none), and a system-assigned managed identity with Reader and Contributor scoped to that resource group plus Key Vault Secrets User; the primary's identity also holds Secrets Officer. The nodes replicate over TCP and UDP 7946, and one Key Vault in the primary region's group is read by both identities. A two-region deployment, one dedicated resource group per region: rg-ne in northeurope and rg-we in westeurope. Each holds a DTM node on a stable private IP (Standard_D2s_v5), an NSG listing the deploy port table (53 DNS, 853 DoT if enabled, 443 DoH if enabled, 8080 Web UI, 8443 API and management, 7946 replication between nodes only), a Premium SSD data disk (64 GiB P6, grows in place, host caching none), and a system-assigned managed identity with Reader and Contributor scoped to that resource group plus Key Vault Secrets User; the primary's identity also holds Secrets Officer. The nodes replicate over TCP and UDP 7946, and one Key Vault in the primary region's group is read by both identities.

Each node runs on Standard_D2s_v5 (2 vCPU, 8 GiB) by default, the smallest size that supports Accelerated Networking for line-rate DNS. Larger sizes suit higher query or dynamic-update rates, though the cluster also scales horizontally: adding nodes is the usual way to add both capacity and resilience.

Each node keeps its full copy of DNS state in a single embedded database on a dedicated Azure Premium SSD managed disk mounted at /var/lib/dtm, attached automatically by the deployment:

Setting Default Why it matters
Disk type Premium SSD (managed) Durable; survives stop, restart, and host maintenance.
Size 64 GiB For durability and compaction headroom, not raw capacity.
Redundancy Locally redundant (LRS) Zone-redundant (ZRS) where the region supports it.
Host caching None Every write reaches durable media before it is acknowledged.

The database is never placed on the VM temporary disk, which Azure wipes on deallocation. Host caching is disabled so a write is durable the moment it is acknowledged, which is what protects your data from a host failure. A DNS control plane’s database is small (megabytes to a few gigabytes even for large estates), so the 64 GiB default leaves ample room for routine compaction; raise the disk to a larger Premium SSD tier if you need more IOPS. These are deploy-time defaults you can adjust, not settings you have to tune by hand.

If you need more IOPS headroom, raise the deployment’s data-disk size parameter and re-apply. The resize is online: Azure grows the disk in place with the VM running, with no restart and no data movement. Moving from the 64 GiB default (P6) to 128 GiB (P10) doubles the IOPS budget, and 256 GiB (P15) roughly doubles it again. The same disk configuration and procedure apply to single-region and dual-region deployments.

Two things to know before you resize:

  • Resize through the deployment parameter, never the Azure portal. A portal resize works at the time, but your template still records the old size, so the next deployment or apply tries to shrink the disk and Azure rejects it.
  • Disks only grow. Azure managed disks cannot shrink, so start at the default and scale up when monitoring says you need it.

Most operators resize purely for IOPS, since the database itself stays small. If you do want the added capacity available to the filesystem, grow it live with growpart and resize2fs; no service restart is needed.

DTM runs entirely on private IPs inside your VNet. The nodes are not assigned public IPs, and you should not add one: DNS and management stay on your private network, where your clients and administrators already are. Reach the nodes over the VNet, a peered VNet, or your existing private connectivity (VPN / ExpressRoute).

Open these ports to the appropriate sources on the subnet’s network security group:

Port Protocol Purpose Source
53 UDP + TCP DNS queries Your VNets / DNS clients
8443 TCP REST API and management Administrators / automation
8080 TCP Web UI (HTTPS; self-signed certificate at first boot, replaceable) Administrators
7946 UDP + TCP Cluster replication between nodes The DTM nodes only
853 TCP DNS-over-TLS (if enabled) Your DNS clients
443 TCP DNS-over-HTTPS (if enabled; a dedicated listener serving only /dns-query) Your DoH resolver clients

The deployment creates this NSG for you and scopes the management ports (8443 and 8080) to the adminAddressPrefix parameter, which defaults to VirtualNetwork (the whole VNet, including peered traffic). Tighten it to the subnet or CIDR your administrators and automation actually use, such as a jumpbox or management subnet. The deployment enforces the value with an explicit deny rule, so once narrowed, other workloads inside the VNet cannot reach the management ports even though they share the network.

The deployment output tells you the API endpoint (for example https://<node-ip>:8443), the web UI URL, and a recoverAdminAccessCommand output that fetches the initial administrator password for you (the Terraform starter’s equivalent output is retrieve_admin_password_command; the Bicep dialect names it retrieveAdminPasswordCommand).

The initial administrator is:

  • Username: admin
  • Password: generated on the primary node at first boot and written to the Key Vault the deployment provisioned, as the secret dtm-initial-admin-password. See how the cluster’s secrets are created.

Retrieve the password with the Azure CLI (or just run the recoverAdminAccessCommand the deployment printed):

Terminal window
az keyvault secret show \
--vault-name <your-vault> \
--name dtm-initial-admin-password \
--query value -o tsv

Log in to the web UI on port 8080 with admin and that password. Change the initial password immediately, then create named users with the least privilege each one needs. See users and access.

DTM has three management surfaces. Pick whichever fits how you work; you can use more than one, but manage any given object in a single place (see the Terraform notes on avoiding drift).

Surface Best for Needs an API token?
Web UI Interactive changes, browsing cluster state No, just log in
Terraform Declarative, version-controlled, repeatable config Yes
REST API Scripting and integrations Yes

Only the Terraform and REST API paths need an API token; web UI users never need one. The Quickstart walks each path through creating your first zone and record.

For Bicep-first estates (Azure Landing Zones), DTM also ships Bicep entry points that share the Marketplace templates’ parameters and contracts: single-region, dual-region, and add-node under deploy/bicep/, available from support (the HA Marketplace topologies are ARM-only today), with the same parameters (imageVersion, adminAddressPrefix, dataDiskSizeGB, and friends), the same NSG rules, and the same secrets-generated-on-the-VM contract. A regionDiscoveryEnabled parameter (default true) controls whether the node runs Azure region discovery; setting it false also skips the local resource-group Reader grant, whose only consumer is the discovery loop. Preview with az deployment group what-if and deploy by copying the example parameter file, editing its values, and pointing both flags at the same directory: cp single-region/main.example.bicepparam single-region/main.bicepparam, then az deployment group create -g <rg> -f single-region/main.bicep -p single-region/main.bicepparam. The modules follow Azure Verified Modules conventions (tags, locks, extra role assignments, diagnostics; telemetry off) but are not registry-published AVM modules, and the Azure Marketplace offer itself remains the supported packaging: Bicep is an authoring alternative, not a different product channel.

One extra template sits apart from the topologies: deploy/bicep/mg-grant/ grants Reader at management-group scope to your node identities, for management-group discovery scopes. It is separate because a role assignment can only be created at or below the deployment’s target scope, and the topologies deploy into a resource group. Deploy it after the cluster, with the principal IDs the topology outputs:

Terminal window
az deployment mg create \
--management-group-id <mg-name> \
--location <region> \
--template-file deploy/bicep/mg-grant/main.bicep \
--parameters principalIds="['<managedIdentityPrincipalId>']"

--location only records where the deployment metadata lives; nothing regional is created. The caller needs Owner or User Access Administrator at the management group: Reader on it is not enough to grant Reader on it.

By default the Terraform deployment creates everything DTM needs: a dedicated resource group, subnet, NSG, Key Vault, and system-assigned identities with their role grants. For estates where the platform team owns those, each is an independent bring-your-own toggle; bring only what your security model requires:

You can bring Toggles
Subnet and NSG create_subnet / existing_subnet_id, create_nsg / existing_nsg_id (you own the rules DTM would otherwise manage)
User-assigned identity and Key Vault create_identity / existing_identity_id, create_key_vault / existing_key_vault_id (a preflight checks the grants you pre-created)
Resource group create_resource_group / existing_resource_group_name (advanced)

(The VNet is always yours: the template only ever references an existing VNet, carving a dedicated subnet in it unless you bring that too.)

Two properties make this safe to adopt: the toggles are additive (all defaults means create-everything, exactly as before), and teardown only ever removes resources DTM created, never a resource group, VNet, Key Vault, or identity you brought; every role assignment DTM created on your scopes is cleanly removed, even when the scope itself is one you brought. The delivered artifacts include a prerequisites checklist covering what to pre-create and pre-grant for each tier, including a per-tier decision table; the least-privilege combination is bringing your own identity and Key Vault, which reduces the deploy principal’s requirement to plain Contributor.

Details worth knowing before you rely on them:

  • The preflight fails fast, not silently. In BYO-identity mode, apply runs a grant check before creating any VM and fails with a clear message if the identity lacks a write-capable Key Vault role on the BYO vault, turning an under-grant from an hour of silent boot retries into an actionable error. It shells out to az, so run Terraform from a host with the Azure CLI logged in (Linux, macOS, WSL, or Cloud Shell). The RG-scoped Reader and Contributor grants are not preflight-checked (they can only be verified at runtime); apply them before the cluster boots or region discovery and the lifecycle orchestrator sit inert.
  • Shared resource groups widen the blast radius. The node identities get Contributor on the deployment resource group so the lifecycle orchestrator can swap VMs; on a shared BYO RG that grant spans everything else in it. Strongly prefer a dedicated RG per region plus a BYO identity, so the grant is scoped and pre-audited. The plan fails early if the existing RG’s region does not match the deployment’s.

Check each node reports ready and the cluster sees all its members. Readiness needs no token:

Terminal window
# 200 = ready to serve; 503 = still starting or joining
curl -sk https://<node-ip>:8443/readyz

To check cluster membership over the API, capture a token first. Login sets the JWT as an HttpOnly dtm_token cookie; capture it from the Set-Cookie header and pass it as a bearer token:

Terminal window
TOKEN=$(curl -sk -X POST https://<node-ip>:8443/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "<initial-password>"}' \
-D - -o /dev/null | grep -i '^set-cookie: dtm_token=' \
| sed -E 's/.*dtm_token=([^;]+).*/\1/')
# Every node should report "alive"
curl -sk https://<node-ip>:8443/api/v1/nodes \
-H "Authorization: Bearer $TOKEN"

Then confirm DNS answers from a node:

Terminal window
dig @<node-ip> example.internal +short