Deploy dual-region DTM
Region-aware answers on private IPs are DTM’s flagship trick, and dual-region is also its highest-silent-failure setup: a missing peering route or a closed cluster port leaves the second node joining forever, and a missing identity grant makes Azure discovery quietly do nothing. This tutorial gates on the prerequisites first, proves each layer before building the next, and ends with a fallback you have actually watched happen.
1. Gate on the prerequisites before spending money
Section titled “1. Gate on the prerequisites before spending money”Two network facts must be true before you deploy.
- Non-overlapping address spaces between the two regions’ VNets, and no subnet NSG, UDR, or hub firewall that blocks traffic between them. This is the number-one cause of a second node stuck joining.
- The two VNets already reach each other. The dual-region samples and the Marketplace 4-node HA, two regions option do not create or change VNet peering. Peer the VNets, or route them through your hub, before you deploy.
You do not need to pre-create NSG rules. The deployment creates each node’s
NSG, allowing 7946 TCP and UDP for cluster replication and 53 from your
DNS client CIDR, per the port table.
Verify cross-region routability with any existing VM pair across the
peering (ICMP, or any port that is already listening). Do not test 7946 yet:
no DTM node exists until step 2, so that port will not answer. Ten minutes
here saves an afternoon of
stuck-joining troubleshooting.
2. Deploy one node per region
Section titled “2. Deploy one node per region”Deploy one node per region with one shared Key Vault in the primary
region, from the dual-region Terraform
or Bicep sample. (The Marketplace
4-node HA, two regions
option deploys two nodes per region with the same shared Key Vault; the
cross-region checks in this tutorial are the same for four nodes.) The
bootstrap is behavioral and worth knowing: the primary node generates the
cluster’s secrets (the initial administrator password and the cluster
encryption key) and publishes them to the vault; the secondary reads the
same vault and retries until they appear, so expect the second node to reach
ready a few minutes after the first. Retrieve the admin password with the
deployment’s retrieve_admin_password_command output
(retrieveAdminPasswordCommand in Bicep, recoverAdminAccessCommand on the
Marketplace);
first login covers it.
3. Verify cluster formation, then prove replication
Section titled “3. Verify cluster formation, then prove replication”Readiness first, on both nodes (the secondary sits at 503 until its first
full copy of cluster state arrives):
curl -sk https://10.0.250.4:8443/readyz # northeurope node: 200curl -sk https://10.1.250.4:8443/readyz # westeurope node: 200Then membership:
curl -sk https://10.0.250.4:8443/api/v1/nodes \ -H "Authorization: Bearer $DTM_TOKEN"# two members, both "status": "alive", each with its regionIf only one member appears, now is the moment to test the replication port
directly, from a VM in one region toward the other node’s IP:
nc -vz 10.1.250.4 7946. It answers only once the node is up, which is why
this check belongs here and not in step 1.
Now prove replication the way that actually matters, write on one node and resolve from the other:
# create zone example.internal. and record app -> 10.0.1.10 on the NE node# (UI, API, or Terraform; see the quickstart), then:dig @10.1.250.4 app.example.internal +short# 10.0.1.10 (written in northeurope, answered from westeurope)4. Teach DTM your regions
Section titled “4. Teach DTM your regions”DTM maps a client to a region by the subnet its query arrives from. Two ways to build that map; pick one:
- Path A, Azure discovery: the deployment ships with
azure.region_discovery_enabledon; add a discovery scope and run it (POST /api/v1/discovery/scopes, thenPOST /api/v1/discovery/run, both admin; add?dry_run=truefirst to preview the diff without writing). Note the periodic loop only detects drift after this; you apply changes from the UI or with another run, unless you setazure.region_discovery_auto_apply: true. The prerequisite is the Reader grant at each scope, and a missing grant fails silently: discovery runs and maps nothing. The antidote is the identity probe surface, the Cluster permissions card on the Lifecycle page (orGET /api/v1/lifecycle/identity), which shows a per-backend read-only probe refreshed every 60 seconds; check it before blaming the mapper. - Path B, manual mappings: explicit and grant-free:
curl -sk -X POST https://10.0.250.4:8443/api/v1/subnet-mappings \ -H "Authorization: Bearer $DTM_TOKEN" -H "X-DTM-CSRF: 1" \ -H "Content-Type: application/json" \ -d '{"subnet": "10.0.0.0/16", "region_id": "northeurope", "source": "manual"}'# repeat for 10.1.0.0/16 -> westeuropeRegions and subnet mapping explains precedence when both sources coexist.
Verify with the right endpoints: GET /api/v1/subnet-mappings lists the
mappings (subnet to region); GET /api/v1/regions returns the deduplicated
region IDs only, so use it as the roll-up check, not the detail view.
5. Health-check the record, then make it region-aware
Section titled “5. Health-check the record, then make it region-aware”First, attach a health check to the record’s values (a TCP probe on the
app port with a 5 second interval, per
health checks; the default interval is 15
seconds, and the explicit 5 keeps step 7’s drill timing tight). This is not
optional garnish: without probes, values never go unhealthy and region
fallback can never trigger.
Then make the record dual-region: add the westeurope backend as a second
value, tag each value with its region (a blank region auto-detects from the
subnet map), and set the policy to region (local first, with an optional
region_preference fallback order) or geo-failover (region filtering plus
round-robin within the selected region).
Load-balancing methods covers the choice, and
its two standing prerequisites: subnet mappings in place, and every node
able to probe backends in both regions (peering is not transitive; if
probes cannot cross, health goes dark from one side).
Verify: GET /api/v1/health/status on each node shows both backends
healthy from that node’s own vantage point.
6. Prove local-first
Section titled “6. Prove local-first”From a client in each region, against that region’s node:
# northeurope clientdig @10.0.250.4 app.example.internal +short # 10.0.1.10
# westeurope clientdig @10.1.250.4 app.example.internal +short # 10.1.1.10Same name, different region, different (local) answer: that is the feature.
7. Drill the cross-region fallback
Section titled “7. Drill the cross-region fallback”Stop the westeurope backend and keep querying from the westeurope
client. The timing is the standard probe math: with the 5 second interval
you set in step 5 and the template’s fixed failure threshold of 3, the
local node marks its backend
unhealthy after about 15 seconds and answers flip to 10.0.1.10, plus the
record TTL as the client-cache floor. Restore the backend; two consecutive
successful probes bring it back.
Two semantics to observe while you watch, both by design:
- Health is per node, never replicated. Each node answers from its own probe view, so run the drill’s digs against the client’s local node; the northeurope node’s view of the westeurope backend is a different (and independently correct) story.
- If every value is unhealthy, DTM fails open: it treats all values as candidates again (so answers never go empty), and your record’s region policy still picks from them. An answer that might reach a recovering backend beats an empty answer that strands every client.
Verify: you saw the flip, the timing matched the math, and recovery returned the local answer.
8. Cut clients over, local node first
Section titled “8. Cut clients over, local node first”Point each region’s VNet DNS at its local node first with the remote node second, so normal resolution stays regional and a node loss fails over to the other region’s node:
az network vnet update -g rg-ne -n vnet-ne --dns-servers 10.0.250.4 10.1.250.4az network vnet update -g rg-we -n vnet-we --dns-servers 10.1.250.4 10.0.250.4(Clients pick the change up on restart or lease renewal.) Then extend your backups and observability to cover both nodes; a dual-region cluster with single-region monitoring is half-finished.
Where next
Section titled “Where next”- Wire observability end to end: dashboards and alerts across both nodes.
- Production readiness pass: the go-live gate, now with two regions in scope.
- Adding nodes (scaling out): a second node per region is the next resilience step.
- Regions and subnet mapping: the mapping model in full.
Need a hand? Email [email protected].
Last validated: 2026-07-26