|
| 1 | +--- |
| 2 | +title: 'DNS Monitor Configuration' |
| 3 | +description: 'Configure your DNS monitor to verify record resolution.' |
| 4 | +sidebarTitle: 'Configuration' |
| 5 | +--- |
| 6 | + |
| 7 | +{/* <Tip> |
| 8 | +To configure a DNS monitor using code, learn more about the [DNS Monitor Construct](/constructs/dns-monitor). |
| 9 | +</Tip> */} |
| 10 | + |
| 11 | +### Basic Setup |
| 12 | + |
| 13 | +Specify the domain and record type you want to check: |
| 14 | + |
| 15 | +<Frame> |
| 16 | + <img className="block dark:hidden" src="/images/dns-monitors/request.png" alt="DNS monitor setup interface showing domain, record type, dns server and protocol" /> |
| 17 | + <img className="hidden dark:block" src="/images/dns-monitors/request-dark.png" alt="DNS monitor setup interface showing domain, record type, dns server and protocol" /> |
| 18 | +</Frame> |
| 19 | + |
| 20 | +* **Domain:** The domain you want to monitor (e.g. `checklyhq.com`) |
| 21 | +* **Record type:** The DNS record to query. See [supported record types](/detect/uptime-monitoring/dns-monitors/overview#supported-dns-record-types) for the full list. |
| 22 | +* **DNS server:** Queries use 8.8.8.8 (Google DNS) by default with automatic failover to 1.1.1.1 (Cloudflare) and an internal AWS resolver on errors. You can specify a custom nameserver and port (e.g., `1.1.1.1:53` or `dns.google:53`) to test resolver-specific behavior |
| 23 | +* **Protocol:** You can pin DNS queries to UDP-only or TCP-only. |
| 24 | + |
| 25 | +### Assertions |
| 26 | + |
| 27 | +Assertions let you define what the expected result of a DNS query should be. |
| 28 | + |
| 29 | +The raw and JSON responses are shown on the results page of a DNS monitor run and can be used as a reference when defining assertions. |
| 30 | + |
| 31 | +<Frame> |
| 32 | + <img className="block dark:hidden" src="/images/dns-monitors/assertions.png" alt="DNS monitor assertions and corresponding data fields" /> |
| 33 | + <img className="hidden dark:block" src="/images/dns-monitors/assertions-dark.png" alt="DNS monitor assertions and corresponding data fields" /> |
| 34 | +</Frame> |
| 35 | + |
| 36 | +* **Response time:** The lookup time in milliseconds. Use this to set thresholds for failed lookups |
| 37 | + |
| 38 | +* **Return code:** By default, DNS monitors pass when the return code is NOERROR and fail on error codes (FORMERR, SERVFAIL, NXDOMAIN, etc.). You can override this behavior by defining a custom return code assertion |
| 39 | + |
| 40 | +* **Text response:** The raw DNS response as plain text. Use this to check for specific strings in the response |
| 41 | + |
| 42 | +* **JSON response:** The DNS response parsed as JSON. This allows you to target specific fields using JSON path assertions. The response structure varies by record type. See [JSON response schemas](#json-response-schemas) below for all supported record types. |
| 43 | + |
| 44 | +With JSON path assertions, you can: |
| 45 | + |
| 46 | +* `$.Answer.length` → verify the number of records returned |
| 47 | +* `$.Answer[0].TTL` → validate TTL values are within expected ranges |
| 48 | +* `$.Answer[0].data` → check specific IP addresses or record values |
| 49 | +* `$.Status` → verify the DNS response status code |
| 50 | + |
| 51 | +Learn more about JSON path assertions: [JSON responses with JSON path](/detect/synthetic-monitoring/api-checks/assertions/#json-responses-with-json-path). |
| 52 | + |
| 53 | +### JSON Response Schemas |
| 54 | + |
| 55 | +The DNS response is parsed into a structured JSON format. All responses share a common structure: |
| 56 | + |
| 57 | +```json |
| 58 | +{ |
| 59 | + "Answer": [ |
| 60 | + // Array of answer records |
| 61 | + ], |
| 62 | + "Question": [ |
| 63 | + { |
| 64 | + "name": "example.com.", |
| 65 | + "type": "A" |
| 66 | + } |
| 67 | + ], |
| 68 | + "Status": "NOERROR", |
| 69 | + "TC": false, |
| 70 | + "RD": true, |
| 71 | + "RA": true, |
| 72 | + "AD": false, |
| 73 | + "CD": false |
| 74 | +} |
| 75 | +``` |
| 76 | + |
| 77 | +**Key fields**: |
| 78 | +- `Answer` - Array of DNS records returned |
| 79 | +- `Question` - The DNS query that was made |
| 80 | +- `Status` - Response status (NOERROR, NXDOMAIN, SERVFAIL, etc.) |
| 81 | +- `TC` - Truncated flag |
| 82 | +- `RD` - Recursion desired flag |
| 83 | +- `RA` - Recursion available flag |
| 84 | +- `AD` - Authenticated data flag |
| 85 | +- `CD` - Checking disabled flag |
| 86 | + |
| 87 | +<Accordion title="A Record (IPv4)"> |
| 88 | +```json |
| 89 | +{ |
| 90 | + "Answer": [ |
| 91 | + { |
| 92 | + "name": "checklyhq.com.", |
| 93 | + "type": "A", |
| 94 | + "TTL": 27, |
| 95 | + "data": "18.66.102.85" |
| 96 | + }, |
| 97 | + { |
| 98 | + "name": "checklyhq.com.", |
| 99 | + "type": "A", |
| 100 | + "TTL": 27, |
| 101 | + "data": "18.66.102.10" |
| 102 | + } |
| 103 | + ], |
| 104 | + "Question": [ |
| 105 | + { |
| 106 | + "name": "checklyhq.com.", |
| 107 | + "type": "A" |
| 108 | + } |
| 109 | + ], |
| 110 | + "Status": "NOERROR", |
| 111 | + "TC": false, |
| 112 | + "RD": true, |
| 113 | + "RA": true, |
| 114 | + "AD": false, |
| 115 | + "CD": false |
| 116 | +} |
| 117 | +``` |
| 118 | + |
| 119 | +Common assertions: |
| 120 | +- `$.Answer[0].data` - Check specific IP address |
| 121 | +- `$.Answer.length` - Verify number of A records |
| 122 | +- `$.Answer[0].TTL` - Validate TTL value |
| 123 | +</Accordion> |
| 124 | + |
| 125 | +<Accordion title="AAAA Record (IPv6)"> |
| 126 | +```json |
| 127 | +{ |
| 128 | + "Answer": [ |
| 129 | + { |
| 130 | + "name": "example.com.", |
| 131 | + "type": "AAAA", |
| 132 | + "TTL": 300, |
| 133 | + "data": "2606:2800:220:1:248:1893:25c8:1946" |
| 134 | + } |
| 135 | + ], |
| 136 | + "Question": [ |
| 137 | + { |
| 138 | + "name": "example.com.", |
| 139 | + "type": "AAAA" |
| 140 | + } |
| 141 | + ], |
| 142 | + "Status": "NOERROR" |
| 143 | +} |
| 144 | +``` |
| 145 | + |
| 146 | +Common assertions: |
| 147 | +- `$.Answer[0].data` - Check IPv6 address |
| 148 | +- `$.Answer[0].TTL` - Validate TTL value |
| 149 | +</Accordion> |
| 150 | + |
| 151 | +<Accordion title="CNAME Record"> |
| 152 | +```json |
| 153 | +{ |
| 154 | + "Answer": [ |
| 155 | + { |
| 156 | + "name": "www.example.com.", |
| 157 | + "type": "CNAME", |
| 158 | + "TTL": 300, |
| 159 | + "data": "example.com." |
| 160 | + } |
| 161 | + ], |
| 162 | + "Question": [ |
| 163 | + { |
| 164 | + "name": "www.example.com.", |
| 165 | + "type": "CNAME" |
| 166 | + } |
| 167 | + ], |
| 168 | + "Status": "NOERROR" |
| 169 | +} |
| 170 | +``` |
| 171 | + |
| 172 | +Common assertions: |
| 173 | +- `$.Answer[0].data` - Verify canonical name target |
| 174 | +</Accordion> |
| 175 | + |
| 176 | +<Accordion title="MX Record"> |
| 177 | +```json |
| 178 | +{ |
| 179 | + "Answer": [ |
| 180 | + { |
| 181 | + "name": "example.com.", |
| 182 | + "type": "MX", |
| 183 | + "TTL": 3600, |
| 184 | + "data": "10 mail.example.com." |
| 185 | + }, |
| 186 | + { |
| 187 | + "name": "example.com.", |
| 188 | + "type": "MX", |
| 189 | + "TTL": 3600, |
| 190 | + "data": "20 mail2.example.com." |
| 191 | + } |
| 192 | + ], |
| 193 | + "Question": [ |
| 194 | + { |
| 195 | + "name": "example.com.", |
| 196 | + "type": "MX" |
| 197 | + } |
| 198 | + ], |
| 199 | + "Status": "NOERROR" |
| 200 | +} |
| 201 | +``` |
| 202 | + |
| 203 | +Common assertions: |
| 204 | +- `$.Answer[0].data` - Check MX priority and mail server (format: "priority hostname") |
| 205 | +- `$.Answer.length` - Verify number of mail servers |
| 206 | +</Accordion> |
| 207 | + |
| 208 | +<Accordion title="TXT Record"> |
| 209 | +```json |
| 210 | +{ |
| 211 | + "Answer": [ |
| 212 | + { |
| 213 | + "name": "example.com.", |
| 214 | + "type": "TXT", |
| 215 | + "TTL": 300, |
| 216 | + "data": "v=spf1 include:_spf.example.com ~all" |
| 217 | + } |
| 218 | + ], |
| 219 | + "Question": [ |
| 220 | + { |
| 221 | + "name": "example.com.", |
| 222 | + "type": "TXT" |
| 223 | + } |
| 224 | + ], |
| 225 | + "Status": "NOERROR" |
| 226 | +} |
| 227 | +``` |
| 228 | + |
| 229 | +Common assertions: |
| 230 | +- `$.Answer[0].data` - Verify SPF, DKIM, or other TXT records |
| 231 | +- Text response contains `v=spf1` - Check for SPF record |
| 232 | +</Accordion> |
| 233 | + |
| 234 | +<Accordion title="NS Record"> |
| 235 | +```json |
| 236 | +{ |
| 237 | + "Answer": [ |
| 238 | + { |
| 239 | + "name": "example.com.", |
| 240 | + "type": "NS", |
| 241 | + "TTL": 86400, |
| 242 | + "data": "ns1.example.com." |
| 243 | + }, |
| 244 | + { |
| 245 | + "name": "example.com.", |
| 246 | + "type": "NS", |
| 247 | + "TTL": 86400, |
| 248 | + "data": "ns2.example.com." |
| 249 | + } |
| 250 | + ], |
| 251 | + "Question": [ |
| 252 | + { |
| 253 | + "name": "example.com.", |
| 254 | + "type": "NS" |
| 255 | + } |
| 256 | + ], |
| 257 | + "Status": "NOERROR" |
| 258 | +} |
| 259 | +``` |
| 260 | + |
| 261 | +Common assertions: |
| 262 | +- `$.Answer.length` - Verify number of nameservers |
| 263 | +- `$.Answer[0].data` - Check specific nameserver |
| 264 | +</Accordion> |
| 265 | + |
| 266 | +<Accordion title="SOA Record"> |
| 267 | +```json |
| 268 | +{ |
| 269 | + "Answer": [ |
| 270 | + { |
| 271 | + "name": "example.com.", |
| 272 | + "type": "SOA", |
| 273 | + "TTL": 3600, |
| 274 | + "data": "ns1.example.com. admin.example.com. 2024010100 7200 3600 1209600 3600" |
| 275 | + } |
| 276 | + ], |
| 277 | + "Question": [ |
| 278 | + { |
| 279 | + "name": "example.com.", |
| 280 | + "type": "SOA" |
| 281 | + } |
| 282 | + ], |
| 283 | + "Status": "NOERROR" |
| 284 | +} |
| 285 | +``` |
| 286 | + |
| 287 | +**SOA data format**: `primary-ns responsible-email serial refresh retry expire minimum` |
| 288 | + |
| 289 | +Common assertions: |
| 290 | +- `$.Answer[0].data` - Verify SOA record (contains serial number and nameserver) |
| 291 | +- Text response contains expected serial number |
| 292 | +</Accordion> |
| 293 | + |
| 294 | +<Note> |
| 295 | +**Record type support**: DNS monitors currently support A, AAAA, CNAME, MX, NS, SOA, and TXT record types. Additional record types (SRV, CAA, PTR, etc.) may be added in future updates. |
| 296 | +</Note> |
| 297 | + |
| 298 | +### Response Time Limits |
| 299 | + |
| 300 | +Define performance thresholds for degraded or failed states: |
| 301 | + |
| 302 | +<Frame> |
| 303 | + <img className="block dark:hidden" src="/images/dns-monitors/response-time.png" alt="DNS monitor response time limits interface" /> |
| 304 | + <img className="hidden dark:block" src="/images/dns-monitors/response-time-dark.png" alt="DNS monitor response time limits interface" /> |
| 305 | +</Frame> |
| 306 | + |
| 307 | +### Frequency |
| 308 | + |
| 309 | +Set how often the monitor runs (every 10 seconds to 24 hours): |
| 310 | + |
| 311 | +<Frame> |
| 312 | + <img className="block dark:hidden" src="/images/dns-monitors/frequency.png" alt="DNS monitor frequency selection interface" /> |
| 313 | + <img className="hidden dark:block" src="/images/dns-monitors/frequency-dark.png" alt="DNS monitor frequency selection interface" /> |
| 314 | +</Frame> |
| 315 | + |
| 316 | +### Scheduling & Locations |
| 317 | + |
| 318 | +<Frame> |
| 319 | + <img className="block dark:hidden" src="/images/dns-monitors/scheduling.png" alt="DNS monitor scheduling strategy and location selection interface" /> |
| 320 | + <img className="hidden dark:block" src="/images/dns-monitors/scheduling-dark.png" alt="DNS monitor scheduling strategy and location selection interface" /> |
| 321 | +</Frame> |
| 322 | + |
| 323 | +* **Strategy:** Choose between round-robin or parallel execution. Learn more about [scheduling strategies](/monitoring/global-locations#scheduling-strategies) |
| 324 | +* **Locations:** Select one or more [public](/monitoring/global-locations/) locations to run the monitor from. |
| 325 | +* **Private locations**: DNS monitors do not currently support private locations. |
| 326 | +### Additional Settings |
| 327 | + |
| 328 | +* **Name:** Give your monitor a clear name to identify it in dashboards and alerts |
| 329 | +* **Tags:** Use tags to organize monitors across dashboards and [maintenance windows](/communicate/maintenance-windows/overview) |
| 330 | +* **Retries:** Define how failed runs should be retried. See [retry strategies](/communicate/alerts/retries) |
| 331 | +* **Alerting:** Configure your [alert settings](/communicate/alerts/configuration), [alert channels](/communicate/alerts/channels), or set up [webhooks](/communicate/alerts/webhooks) for custom integrations |
| 332 | + |
| 333 | +## Common Use Cases |
| 334 | + |
| 335 | +<Accordion title="Monitor CDN failover with multiple A records"> |
| 336 | +**Scenario**: Your CDN provides multiple IP addresses for redundancy. You need to ensure all IPs are reachable. |
| 337 | + |
| 338 | +**Configuration**: |
| 339 | +- **Domain**: `cdn.example.com` |
| 340 | +- **Record type**: A |
| 341 | +- **Assertions**: |
| 342 | + - `$.Answer.length` equals `4` (verify all IPs present) |
| 343 | + - `$.Answer[0].TTL` is less than `300` (ensure low TTL for quick failover) |
| 344 | + - `$.Answer[0].data` equals expected IP address |
| 345 | +</Accordion> |
| 346 | + |
| 347 | +<Accordion title="Verify email security records (SPF, DKIM, DMARC)"> |
| 348 | +**Scenario**: Monitor SPF, DKIM, and DMARC records to prevent email spoofing. |
| 349 | + |
| 350 | +**Configuration**: |
| 351 | +- **Domain**: `example.com` |
| 352 | +- **Record type**: TXT |
| 353 | +- **Assertions**: |
| 354 | + - Text response contains `v=spf1` |
| 355 | + - `$.Answer[0].data` contains `v=spf1` |
| 356 | + |
| 357 | +For DMARC: |
| 358 | +- **Domain**: `_dmarc.example.com` |
| 359 | +- **Record type**: TXT |
| 360 | +- **Assertions**: |
| 361 | + - Text response contains `v=DMARC1` |
| 362 | + - `$.Answer[0].data` contains `p=reject` or `p=quarantine` |
| 363 | +</Accordion> |
| 364 | + |
| 365 | +<Accordion title="Monitor mail server configuration"> |
| 366 | +**Scenario**: Ensure primary and backup mail servers are correctly configured. |
| 367 | + |
| 368 | +**Configuration**: |
| 369 | +- **Domain**: `example.com` |
| 370 | +- **Record type**: MX |
| 371 | +- **Assertions**: |
| 372 | + - `$.Answer.length` is greater than `1` (at least 2 MX records) |
| 373 | + - `$.Answer[0].data` contains `10 mail.example.com.` (priority 10 + hostname) |
| 374 | + - Text response contains `mail.example.com` |
| 375 | +</Accordion> |
| 376 | + |
| 377 | +<Accordion title="Test DNS propagation after zone transfer"> |
| 378 | +**Scenario**: After updating nameservers, verify all nameservers return consistent results. |
| 379 | + |
| 380 | +**Configuration**: |
| 381 | +- **Domain**: `example.com` |
| 382 | +- **Record type**: NS |
| 383 | +- Create separate monitors for each nameserver: |
| 384 | + - Monitor 1: DNS server `ns1.example.com:53` |
| 385 | + - Monitor 2: DNS server `ns2.example.com:53` |
| 386 | +- **Assertions**: |
| 387 | + - `$.Answer.length` equals expected count |
| 388 | + - `$.Answer[0].data` equals `ns1.example.com.` or `ns2.example.com.` |
| 389 | +</Accordion> |
0 commit comments