DNS Monitoring
Watch your DNS records for silent changes — hijacks, bad zone edits, expired failovers — and get told the moment the answer stops being the one you expect.
What is a DNS monitor?
A DNS monitor resolves one hostname's records on a schedule, compares what came back against a stored baseline, and goes Down when the answer changes or the lookup fails.
Example: "example.com should resolve to 93.184.216.34 and nothing else. If that ever stops being true, page me."
DNS is the one dependency where nothing breaks visibly until everything does. Your site can be healthy, your certificate valid, your servers idle — and if someone changes an A record at your registrar, every visitor lands somewhere else while your uptime monitor still says 100%. A DNS monitor is what notices.
When to use one
- Hijack and takeover detection. A changed NS or A record is one of the first observable signs of a compromised registrar or DNS account.
- Zone-edit safety net. Someone updates a record in a hurry and fat-fingers it. You find out in minutes, not from customers.
- Mail deliverability. Watch your MX records, or the SPF fragment inside a TXT record, so a rewritten DNS entry doesn't quietly break email.
- Failover verification. After you cut over to a new provider, confirm the new answer stuck in the places that matter.
- Certificate issuance control. Watch your CAA records so a new certificate authority can't be authorised without you knowing.
When not to. A DNS monitor tells you what your records say, not whether the thing behind them is alive. If you want "is my site up", use a Website monitor — and run both. They answer different questions and fail independently.
How it works
Every check, Enori:
- Resolves your hostname for the record type you chose.
- Normalises what came back into a canonical, order-independent set.
- Compares it against the baseline and applies any thresholds you've set.
What counts as Up: the lookup succeeded and the resolved set still matches your baseline (or you have no baseline yet, in which case the first successful check stores one and reports Up).
What counts as Down:
| Reason | What happened |
|---|---|
| Record changed | The resolved set no longer matches the baseline. The error names exactly what was added and removed. |
| Domain does not exist | The name is gone, or its delegation is broken — the authoritative answer was NXDOMAIN. |
| Resolution error | The lookup failed for any other reason — no answer, resolver unreachable, refused, timeout. |
| No records | You're watching a specific record type and the host has none of it (e.g. a CNAME monitor on a hostname with no CNAME). |
| Record count | The number of answers fell outside your min/max range. |
| DNSSEC failure | The resolver actively failed validation for the zone. |
| Invalid match pattern | Your Regex expected-value doesn't compile, or took longer than 1 second to evaluate. |
What does not take you Down: a TTL above your ceiling (a warning indicator only), an unsigned zone when DNSSEC is requested, and a cross-region divergence (a security advisory that never touches your uptime figure). Each is explained below.
How often. You pick the interval when you create the monitor — 1 minute through 24 hours, defaulting to 5 minutes. A 30-second interval is available as an add-on. While a monitor is Down, Enori re-checks more frequently so recovery is picked up quickly.
Setting one up
Go to Monitors, click Add Monitor, and pick DNS. The wizard has two steps — Type and Configure — and everything below lives on the Configure step.
Screenshot: the DNS option on the monitor-type picker (step 1).
1. Monitor Name (required)
Anything you'll recognise in an alert at 3am. e.g. "example.com — A record".
2. Group (optional)
Put related monitors together, or leave it ungrouped.
3. Hostname (required)
The bare hostname — example.com, mail.example.com. No scheme, no path.
4. Record Type
Defaults to A. Ten types are available:
| Type | What you're watching |
|---|---|
| A | IPv4 address. The most common choice. |
| AAAA | IPv6 address. |
| CNAME | The alias target. Note that an apex domain cannot have one. |
| MX | Mail exchangers — hostname and priority. |
| NS | The zone's nameservers. The strongest hijack signal there is. |
| TXT | Free-form text — SPF, DKIM, domain-verification strings. |
| SOA | Start of authority — the zone's primary nameserver and serial. |
| SRV | Service location records. |
| CAA | Which certificate authorities may issue for your domain. |
| PTR | Reverse lookups. |
One monitor watches one record type. To watch A and MX for the same domain, create two monitors — Enori allows the same hostname twice as long as the record type differs.
Why not "all types at once"? SOA serials and NS sets rotate as a normal part of zone operation, so a monitor watching everything would alert constantly for no reason.
There is also an A + AAAA (default) mode, which queries both address types and stays Up as long as at least one answers — useful for dual-stack hosts. It isn't offered in the create wizard (which always picks a concrete type); select it in Edit on the monitor afterwards if you want it.
5. Expected Value (optional)
The value or values you expect back. Multiple values are comma-separated: 1.2.3.4, 5.6.7.8.
Leave it blank and Enori seeds the baseline for you from the first successful check — usually what you want. Fill it in when you want to assert a specific answer from the start, or when you're using Contains/Regex matching (below).
6. Match Mode
How your expected values are compared. Defaults to Exact.
| Mode | Behaviour | Pick it when |
|---|---|---|
| Exact — full set match | The resolved set must equal the baseline exactly. Anything added or removed is a change. | You know the complete, stable answer. Most A / CNAME / NS monitors. |
| Contains — substring of a record | Each expected value must appear inside at least one resolved record. Extra records are fine. | You care about a fragment — e.g. include:_spf.google.com inside a TXT record you don't otherwise control. |
| Regex — pattern match | Each expected value is a case-insensitive .NET regular expression that must match at least one record. | The answer varies but follows a shape — e.g. ^A:203\.0\.113\.\d+$ for a pool inside one subnet. |
Two things worth knowing:
- Only Exact fails on extra records. Contains and Regex allow additional values; they fail only when one of your expected entries matches nothing.
- Invalid regex is rejected when you save, so you find out immediately rather than on the next check. A pattern that compiles but takes over 1 second to evaluate is stopped at check time and reported as an invalid-match failure.
7. Custom resolver (optional)
Query a specific DNS server instead of the default one — e.g. 8.8.8.8 to check what a major public resolver currently sees.
Private and reserved addresses are rejected when you save. You cannot point a monitor at an internal resolver.
8. TTL ceiling (optional)
A whole number of seconds. When the observed TTL exceeds it, the detail page shows an "Above ceiling" badge next to the TTL.
Be clear about what this is: a hygiene indicator, not an alert. It never changes the monitor's status and it never sends a notification. It's there so you can spot a record whose TTL is too long to fail over quickly when you look at the page. Leave it blank for no ceiling.
9. Min records / Max records (optional)
Whole numbers, side by side. If the number of answers falls below the minimum or above the maximum, the check goes Down.
Worked example: an autoscaled pool that should always publish between 3 and 8 A records. Set Min 3, Max 8. If the pool drops to 2, you're paged — even though every remaining record is perfectly valid and Exact matching would have said nothing was wrong.
Min must be less than or equal to Max, and the count check runs before the change comparison — so if both would trip, you'll see the count failure.
10. Require DNSSEC (optional, off by default)
Ask a DNSSEC-aware resolver to validate the zone and record what it says.
What this actually is: Enori reads the resolver's Authentic Data verdict — its answer to "did this zone validate?" — and shows it. Enori does not verify the signature chain itself. It is resolver trust, not independent cryptographic verification. Treat the badge accordingly.
Three outcomes:
| Badge | Meaning | Effect on status |
|---|---|---|
| Validated by resolver | The zone is signed and the resolver validated it. | Up |
| Insecure | Validation was requested but the resolver reported no validated data — usually an unsigned zone. | Up — warning only |
| Bogus | Validation actively failed — a broken or expired chain, or tampering. | Down |
11. Cross-region consistency (optional, off by default)
Periodically resolve the record from every available checking region and compare the answers. This is the poisoning / hijacking / split-horizon check — see Cross-region consistency below.
When you tick it, a Strict — alert on any IP difference sub-checkbox appears. Leave strict off for anything behind a CDN or GeoDNS.
12. Primary Region
Where the regular checks run from — Automatic, or a specific region. Regions that aren't currently available are greyed out.
13. Check Interval
Defaults to 5 minutes. Options run from 1 minute to 24 hours; 30 seconds requires the add-on.
14. Alert settings
Below the divider on the same step:
- When to alert — how many consecutive failures before you're notified. Defaults to 2 consecutive failures, which absorbs a single flaky lookup.
- Notify me via — which of your alert channels to use.
- Repeat Alerts — whether to keep reminding you while it stays Down.
Then click Create Monitor.
The first check is staggered within your interval rather than run on the spot — with the 5-minute default it lands somewhere in the next five minutes. That's deliberate: it spreads load so a batch of new monitors doesn't fire at once. If you want an answer now, open the monitor and hit Check Now.
Screenshot: the completed DNS Configure step with record type, expected value and match mode filled in.
The baseline
The baseline is the answer set your monitor considers correct. Everything about DNS change detection turns on it.
How it gets set:
- Automatically — if you leave Expected Value blank, the first successful check stores whatever resolved. Convenient, but it trusts that moment: if the record is already wrong when you create the monitor, you've baselined the wrong answer.
- Explicitly — whatever you type into Expected Value. In Exact mode a bare value like
1.2.3.4is stored in canonical form asA:1.2.3.4, which is why the detail page shows the type prefix.
When it resets: changing the record type or the custom resolver clears the baseline, because the old answer no longer describes what's being asked. It re-seeds on the next check.
The Refresh Baseline button
On the monitor's detail page, the DNS Records panel has a Refresh Baseline button. It re-resolves the record right now and stores that as the new expected set. Use it after a change you made on purpose.
Three things to know before you click it:
- It is Exact-mode only. Under Contains or Regex your expected values are patterns you wrote, and overwriting them with whatever resolved at that instant would destroy them and silently convert the monitor to exact matching. So Enori refuses, with an error telling you to edit the patterns instead.
- The status settles on the next check, not instantly. Refreshing does not mark the monitor Up. A monitor that is Down stays Down; anything else moves to Unknown. A real check is queued straight away and that is what produces the status — along with resolving the incident, closing the alert and sending the recovery notification. Expect the page to catch up within a few seconds, not immediately on click.
- It's recorded in your audit log. Rewriting the baseline is the one action that can make a hijacked record look correct, so it's tracked like any other security-relevant change.
Cross-region consistency in detail
With cross-region consistency on, Enori resolves your record from every healthy checking region roughly every 15 minutes and compares the answers.
The comparison is deliberately tiered, because legitimate global infrastructure varies some records and never varies others:
| What differs between regions | Verdict |
|---|---|
| Nameservers (NS) or the zone's primary nameserver (SOA) | Divergent — always. Authority records don't legitimately differ by geography. |
| DNSSEC posture — one region validates, another actively FAILS validation | Divergent — always. Requires Require DNSSEC on the monitor. A region whose resolver simply doesn't validate (Insecure) is a property of that resolver, not evidence about your zone, and is ignored. |
| CNAME target pointing somewhere unrelated in one region | Divergent — always. Targets under a known CDN or your own domain are treated as legitimate. |
| A / AAAA addresses | Not divergent by default — that's ordinary CDN/GeoDNS behaviour. Flagged only in strict mode. |
Strict mode is for domains whose address must be identical worldwide. Turn it on for an apex you host yourself; leave it off for anything fronted by a CDN, or you'll get alerted for your CDN doing its job.
The three badges
The Cross-region DNS consistency panel on the detail page shows the verdict plus a per-region table of exactly what each region resolved.
| Badge | Meaning |
|---|---|
| Consistent across regions | Every region agrees. |
| Divergence detected — confirming | One sweep saw the regions disagree, and Enori is waiting for the next one before calling it. A single disagreement is usually propagation lag or a mid-update change, so it takes two consecutive sweeps to confirm. Nothing has alerted yet. |
| Divergent across regions | Confirmed. The table highlights which regions differ from the majority, and the panel timestamps when it was first confirmed. |
| Not yet evaluated | Fewer than two regions have reported, or the first sweep hasn't finished. |
Divergence never changes your uptime. It's a security advisory, deliberately kept separate from availability — your monitor can be perfectly Up and divergent at the same time. It fires once per confirmed flip (a sustained divergence doesn't re-notify) and resolves on its own when the regions agree again.
Turning the toggle on is enough to be told. A confirmed divergence you haven't routed goes to your normal alert channels at Warning — it reaches email and Slack, and deliberately does not start an escalation ladder. If you want it to page someone, route Cross-region divergence to Critical and the channels you want in Alert Settings → DNS condition routing; an explicit route always wins. If you want it tracked on the page and never sent anywhere, give it a route with no channels selected.
Reading the results
The DNS detail page shows the standard monitor hero (current status, uptime, response time chart, recent checks) plus three DNS-specific panels.
DNS Records
Side-by-side Expected (Baseline) and Current value chips. When the latest check detected a change you also get a "DNS records have changed" banner listing what was Added (green) and Removed (red) — that list is the fastest way to see what actually moved.
If Expected reads "No baseline set" and Current has values, the monitor hasn't stored its baseline yet; it will after the next successful check.
DNS Configuration
| Field | What it shows |
|---|---|
| Record Type | The type being watched (or "All" for the A + AAAA default). |
| DNS Server | Your custom resolver, or "System default". |
| Timeout | How long a lookup may take. |
| TTL | The lowest TTL observed on the last check, with an "Above ceiling" badge if you set a ceiling and it was exceeded. |
| DNSSEC | Shown only when Require DNSSEC is on — the resolver's verdict badge. |
Cross-region DNS consistency
Shown only when the toggle is on. The verdict badge plus a region-by-region table of resolved values.
Screenshot: a DNS detail page mid-change, showing the "DNS records have changed" banner with Added/Removed chips.
Alerts
DNS monitors use the same alerting as every other monitor type — channels, escalation policies, on-call schedules, maintenance suppression. See the Alerts guide for the full picture, and Maintenance windows for suppressing planned zone changes.
By default, any of the Down reasons listed earlier fires your normal Down alert after your failure threshold is met, and recovery fires the usual recovery alert.
Per-condition routing
DNS monitors add one thing the other types don't have: you can route specific DNS failures to specific channels with their own severity. A record change and a nameserver hijack don't deserve the same treatment.
Open the monitor's Alert Settings and find DNS condition routing. Six conditions can be routed independently:
| Condition | Fires when |
|---|---|
| Resolution error | The lookup failed — resolver unreachable, refused, timeout, or no records. |
| Domain does not exist | The authoritative answer was NXDOMAIN: the name is gone or its delegation is broken. |
| Record changed | Resolved records drifted from the baseline. |
| Record count | The answer count fell outside your min/max. |
| DNSSEC failure | The resolver returned a validation failure. |
| Cross-region divergence | Records differ across regions — possible poisoning or hijacking. Requires the cross-region consistency toggle. |
For each, pick a severity (Info / Warning / Critical) and click the channels it should go to.
Worked example: send Record changed at Warning to your team's Slack channel, and Cross-region divergence at Critical to PagerDuty. A routine record edit shows up in chat; a possible hijack wakes someone up.
Cross-region divergence falls back too, with one difference: the per-check conditions fall back to your monitor's Down alert, while divergence never takes the monitor Down — so it falls back to your normal channels at Warning. Either way, not routing a condition never makes it silent. The one way to silence a condition on purpose is to give it a route with no channels selected.
"Domain does not exist" used to be part of "Resolution error", and it still falls back to it: if you have Resolution error routed but not Domain does not exist, an NXDOMAIN follows your Resolution error route exactly as it did before. Nothing you already configured goes quiet. Route it separately only when you want a different severity or different channels — the distinction worth making is that a resolver timeout usually clears itself, while a name that stopped existing does not.
A condition routes only when you've selected at least one channel for it — otherwise your normal channels apply. Routing is configured after the monitor exists, because it references alert channels the create wizard hasn't attached yet.
The TTL ceiling is not routable. It is a page indicator only, with no alert of any kind.
FAQ
Can one monitor watch several record types?
No — one type per monitor. Create separate monitors for A, MX and TXT on the same domain; Enori doesn't count those as duplicates because the record type differs.
Why does my baseline show A:1.2.3.4 instead of 1.2.3.4?
In Exact mode, values are stored in a canonical TYPE:value form so the comparison is unambiguous — an A record of 1.2.3.4 is not the same thing as a TXT record containing 1.2.3.4. You can still type bare values into Expected Value; Enori adds the prefix.
Does a DNS change count against my uptime?
Yes. A detected record change is a Down check and counts like any other downtime, including in SLOs and reports. The one exception is cross-region divergence, which is a security advisory and never affects uptime.
I want to know about changes without hurting my uptime figure.
Use a maintenance window around planned zone edits — checks keep running but alerts and incidents are suppressed and the window is excluded from your numbers.
Does the TTL ceiling send an alert?
No. It shows an "Above ceiling" badge on the detail page and nothing else. It never changes status and it cannot be routed to a channel.
Does Enori verify DNSSEC signatures?
No. Enori asks a DNSSEC-aware resolver whether the zone validated and reports that answer. It does not walk or verify the signature chain itself. An unsigned zone is reported as Insecure and stays Up; an actual validation failure is reported as Bogus and goes Down.
Will my CDN trip the cross-region check?
Not by default. Address records are expected to vary between regions, so they're ignored unless you enable strict mode. Nameserver and SOA differences are always treated as divergence, because those don't legitimately vary by geography. DNSSEC counts only when one region validates and another fails validation — a region whose resolver doesn't validate at all is ignored, since that says nothing about your zone.
Can I point a monitor at my internal DNS server?
No. Private and reserved addresses are rejected when you save the monitor. The custom resolver has to be publicly reachable.
How quickly will I hear about a change?
Your check interval plus your failure threshold. At the defaults — 5 minutes, 2 consecutive failures — that's roughly 10 minutes. Tighten the interval for records where minutes matter.
Can I manage DNS monitors through the API?
Yes — see the API reference and the MCP server.
Troubleshooting
"DNS_CHANGED" but the record looks right
This is the most common report, and the monitor is usually correct — something did change; it just wasn't you.
- Read the Added / Removed values first. The error message and the detail-page banner name exactly which values moved. That normally identifies the cause in seconds.
- Your provider changed something. An added AAAA record, a rotated MX, an extra address in a pool, a rewritten TXT — all of these are real changes to the full set. In Exact mode, an addition is as much a change as a removal.
- You made the change on purpose. Click Refresh Baseline to adopt the current answer.
- You wanted to match a fragment, not the whole set. If you only care that an SPF include is present, switch Match Mode to Contains — Exact requires the complete set to match, with nothing extra.
- Your provider returns a rotating subset. Some resolvers return a different slice of a large pool each time, which will flap under Exact. Use Contains for the value you care about, or drop expected values entirely and use Min/Max records to assert the pool's size instead.
Nothing has happened since I created the monitor
The first check is staggered within your check interval instead of running on creation, so with the 5-minute default you may wait up to five minutes. Use Check Now on the monitor to force one immediately.
The monitor is Up but says "No baseline set"
The baseline is stored by the first successful check. If Current has values and Expected doesn't, wait one interval. If it persists, the checks aren't succeeding — look at the recent-checks list for the actual error.
"No records found" for a type that exists
You're watching a record type this hostname doesn't have. The classic case is a CNAME monitor on an apex domain — apex records can't be CNAMEs. Either point the monitor at the subdomain that does have the CNAME, or switch to A.
Note this only applies while seeding: a record that existed and was later removed reports as a change, not as missing records.
"DNS_ERROR" started right after I set a custom resolver
The resolver is refusing, unreachable, or rate-limiting you. Clear the Custom resolver field to fall back to the default and confirm the record resolves at all, then reintroduce the resolver.
"DNS_MATCH_INVALID"
One of three things. Too much work: your patterns × resolved records would exceed 2,000 evaluations, or the matching passed its 10-second budget for the check — the message says which. Too slow: a single evaluation took more than 1 second; look for nested quantifiers like (a+)+. Invalid: the pattern doesn't compile (normally caught when you save). Use fewer or narrower patterns, or Contains if you only need a substring.
"DNS record count …" when the values look fine
The count check runs before the change comparison, so if the set both shrank past your floor and differs from the baseline, you'll see the count error. That's intentional — a shrinking pool is the more urgent signal. Check your Min/Max settings against what the record legitimately publishes.
Refresh Baseline didn't fix the status
Expected. Refreshing stores the new baseline and queues a check; it deliberately doesn't assert a healthy status. A Down monitor stays Down until a real check succeeds — which is what closes the incident and sends the recovery alert. Give it a few seconds.
If you got an error mentioning match mode instead, the monitor is in Contains or Regex mode, where refresh is blocked on purpose. Edit the expected values directly.
The cross-region panel says "Not yet evaluated"
The comparison runs about every 15 minutes and needs at least two regions to have reported. Give it a sweep or two after enabling the toggle.
Reference: limits and defaults
| Setting | Value |
|---|---|
| Record types | A, AAAA, CNAME, MX, NS, TXT, SOA, SRV, CAA, PTR (one per monitor) |
| Record type default | A in the create wizard; "A + AAAA (default)" available in Edit |
| Match modes | Exact (default), Contains, Regex |
| Expected values | Up to 100 entries, up to 512 characters each |
| Regex | .NET syntax, case-insensitive. Three bounds per check: 1 second per evaluation, 2,000 pattern × record evaluations, and 10 seconds total |
| Resolved values compared per check | Up to 100. Above 100 the whole set is discarded for that check — it is not truncated, because a silently truncated answer set would compare unequal against your baseline and report a change that didn't happen |
| Min / Max records | Whole numbers from 1; min must be ≤ max |
| TTL ceiling | Whole seconds from 1; warning indicator only |
| Custom resolver | Public IP or hostname; private/reserved rejected |
| Check interval | 30 seconds (add-on), 1m, 2m, 5m, 10m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 24h — default 5 minutes |
| Failures before alert | 1, 2, 3 or 5 — default 2 |
| Cross-region sweep | About every 15 minutes; needs ≥2 regions; 2 consecutive sweeps to confirm a divergence |
| Routable alert conditions | Resolution error, Domain does not exist, Record changed, Record count, DNSSEC failure, Cross-region divergence |
Related documentation
- Alerts — channels, escalation policies and on-call rotas
- Maintenance windows — suppress alerts during planned zone changes
- SLOs — reliability targets and error budgets
- Uptime reports — exportable uptime and SLA reports
- Audit log — including baseline refreshes
- API reference and MCP server — programmatic management
Feedback or corrections: support@enori.io