This page is the reference for the server configuration file,
/etc/dtm/dtm-server.yaml on a deployed node. The deployment writes a working
file for you at first boot; you only edit it for the boot-time settings below
that have no API surface.
Strict validation. An unknown or misspelled key anywhere in the file
stops startup with an error naming the offending field, so a typo fails
loudly instead of being silently ignored (see
troubleshooting).
An empty or comments-only file is fine: the server starts with defaults.
Restart to apply. File edits take effect at the next service restart.
Restart one node at a time: a node stops answering DNS while it
restarts.
Environment overrides. Keys marked with a DTM_* name below can be set
as environment variables, which win over the file. List values are
comma-separated. A malformed value stops startup rather than being ignored.
The deployment uses this convention itself to deliver secrets (the cluster
encryption key, the Entra client secret) from Key Vault into a root-only
environment file, so secret values never appear in the YAML.
The file is per node. Apply the same edit on every node unless a setting
is genuinely node-specific (listen addresses, node identity).
Most day-to-day settings are not in this file. Zones, records, health
checks, forwarders, the blocklist, subnet mappings, and TSIG keys are managed
through the API, Terraform,
and the UI, and replicate cluster-wide. Several config sections below also
have a runtime endpoint that is the preferred surface; for those, the YAML is
only the initial seed, and once a runtime change has been made the persisted
value wins over the YAML at the next boot:
UDP DNS bind address. The deployment binds the VM’s private IP, not all interfaces.
listen.dns_tcp
":53"
DTM_LISTEN_DNS_TCP
TCP DNS bind address.
listen.api
":8443"
DTM_LISTEN_API
REST API (HTTPS) bind address.
listen.dot.enabled
false
none
Serve DNS-over-TLS on listen.dot.listen_addr. Boot default only; the runtime toggle wins.
listen.dot.listen_addr
":853"
none
DoT bind address (host:port).
listen.doh.enabled
false
none
Serve DNS-over-HTTPS (/dns-query) on a dedicated listener at listen.doh.listen_addr. Boot default only; the runtime toggle wins. Unauthenticated by spec: gate port 443 at the NSG first.
listen.doh.listen_addr
":443"
none
DoH bind address (host:port).
listen.tls.cert_file
empty
DTM_TLS_CERT_FILE
TLS certificate for the API (and DoT/DoH). Empty means a fresh self-signed certificate at every service start; set both file keys for a stable, trusted cert.
listen.tls.key_file
empty
DTM_TLS_KEY_FILE
Private key matching cert_file. Must be owner-readable only; both keys must be set together, and a missing file stops startup.
listen.tls.ca_file
empty
DTM_TLS_CA_FILE
Advanced: enables mutual TLS. Every API client (including each node’s own UI service) must then present a certificate signed by this CA.
listen.dns_listeners
1
none
DNS listener socket replicas for high query rates. Worth raising toward the vCPU count on 8+ vCPU nodes.
Allow script health-check probes. See the caution below before enabling.
api_allowed_hosts
empty (no enforcement)
none
Host-header allowlist for the API, a DNS-rebinding defence. The server warns at startup when unset.
api_rate_limit.*
built-in defaults
none
Per-IP API rate limits by class (auth_rps/auth_burst, write_rps/write_burst, read_rps/read_burst, upload_rps/upload_burst); the upload class covers the disk-staging endpoints (/api/v1/restore, /api/v1/admin/compact) with a deliberately severe built-in default (1 request per 600 s). Prefer PUT /api/v1/config/rate-limits.
api_rate_limit.trusted_proxies
empty
none
CIDRs allowed to set X-Forwarded-For. Deliberately file-only: when empty, forwarded headers are ignored and the peer address is used.
axfr.enabled
false
none
Allow zone transfers (AXFR).
axfr.allowed_cidrs
empty (all, when enabled)
none
Restrict transfers to these networks.
axfr.require_tsig
false
none
Require TSIG-signed, per-zone-authorized transfer requests.
axfr.notify_targets
empty (no NOTIFY)
DTM_AXFR_NOTIFY_TARGETS
host:port list sent an RFC 1996 DNS NOTIFY on every zone-content change, so mirrors stop polling SOA serials.
axfr.notify_tsig_key_name
empty (unsigned)
DTM_AXFR_NOTIFY_TSIG_KEY_NAME
Sign NOTIFYs with this stored TSIG key. Key rotation applies without a restart; a missing key fails closed rather than sending unsigned.
axfr.notify_debounce_seconds
0 = 5
DTM_AXFR_NOTIFY_DEBOUNCE_SECONDS
Per-zone quiet window: a bulk import produces one NOTIFY, not hundreds. Like the rest of axfr, the NOTIFY keys are boot seeds for the runtime record (PUT /api/v1/config/axfr, live, cluster-wide).
forwarder_hardening.qname_allowlist
empty (no restriction)
none
Suffix allowlist for names the default forwarder will resolve.
The file can seed zones and records at first boot (zones: with name,
default_ttl, soa, records), but in production zones are owned by the
API, Terraform, and the UI once the cluster is
running. Do not manage ongoing DNS data through the file.