Skip to content

DNS Monitoring

Monitoring Module DNS

DNS Monitoring watches specified DNS records for your domains and alerts you whenever they change. You choose exactly which records to track — A, MX, NS, TXT, and more — and NOB.center notifies you whenever any value, TTL, or DNSSEC status changes.


How it works

  1. You add a domain to DNS monitoring and select which DNS records to watch.
  2. NOB.center checks those records on a regular schedule.
  3. When the current values differ from the last known snapshot, a change event is generated.
  4. Your alert rules evaluate each change and dispatch notifications if conditions are met.
  5. The full history of snapshots and diffs is available for review at any time.

Adding a domain

Navigate to DNS Monitoring and click Add Domain. Enter the domain name and choose whether to enable Auto-discover.

Auto-discover

When auto-discover is enabled, NOB.center probes the domain for common DNS record types on the first check and suggests a set of records to monitor. You can review the suggestions and accept or discard each one individually.

Auto-discover probes for: A, AAAA, MX, NS, TXT, CAA, SOA, CNAME, and common subdomains (www, mail, smtp, ftp, etc.).

As long as auto-discovery is enabled NOB.center will probe for these records daily and add as needed.

Domain settings

Field Description
Domain name The fully-qualified domain to monitor (e.g. example.com)
Auto-discover Whether to propose records automatically on first check
Enabled Toggle to pause monitoring without deleting configuration
Notes Free-text label visible in the domain list

dns-add-domain-modal.png

The Add Domain modal

dns-domains-list.png

The DNS Monitoring domain list with status indicators


Managing DNS records

Open a domain to see its Records tab. Each row shows the record name, type, whether it is currently enabled, and how it was added (automatically or manually).

Record types

NOB.center monitors these DNS record types:

A · AAAA · MX · NS · TXT · CNAME · CAA · SOA · SRV · PTR

Enabling and disabling records

Toggle any record on or off individually. A disabled record is paused — it stops consuming quota and no alerts fire for it, but its history is preserved. You can re-enable it at any time.

Adding records manually

Click Add Record, enter a record name and type, and confirm. The record will be queried on the next scheduled check.

Removing records

Delete a record to remove it from monitoring entirely. Its history is retained for 30 days.

dns-records-tab.png

The Records tab showing monitored records and their current enabled state


History and diffs

The History tab shows a timestamped list of snapshots taken for the domain. Click any two snapshots to see a side-by-side diff of what changed between them.

Each diff shows:

Column Description
Record The DNS record name and type
Action added, modified, or deleted
Old values Previous record value(s)
New values New record value(s)
TTL change Old TTL → New TTL (in seconds)
DNSSEC status Validation state at the time of the snapshot

dns-history-list.png

Snapshot history list for a domain

dns-diff-view.png

Side-by-side diff view between two snapshots


Alert rules

Navigate to DNS Monitoring → Alert Rules to create and manage rules for this module.

CEL context object

Each DNS change event exposes the following fields to your CEL conditions:

{
  "domain": "example.com",
  "tld": "com",
  "current": {
    "dns": {
      "example.com": {
        "@": {
          "A": { "values": ["93.184.216.34"], "ttl": 3600 },
          "NS": { "values": ["ns1.example.com", "ns2.example.com"], "ttl": 86400 },
          "MX": { "values": ["10 mail.example.com"], "ttl": 3600 }
        },
        "www": {
          "A": { "values": ["93.184.216.34"], "ttl": 3600 }
        }
      }
    }
  },
  "previous": {
    "dns": {
      "example.com": {
        "@": {
          "A": { "values": ["93.184.216.33"], "ttl": 3600 },
          "NS": { "values": ["ns1.example.com", "ns2.example.com"], "ttl": 86400 },
          "MX": { "values": ["10 mail.example.com"], "ttl": 3600 }
        }
      }
    }
  },
  "changed_records": [
    {
      "name": "@",
      "type": "A",
      "action": "modified",
      "old_values": ["93.184.216.33"],
      "new_values": ["93.184.216.34"],
      "old_ttl": 3600,
      "new_ttl": 3600,
      "dnssec_status": "validated"
    }
  ],
  "metadata": {
    "fetched_at": "2026-01-15T10:30:00Z",
    "nameserver": "8.8.8.8",
    "response_time_ms": 42,
    "query_status": "NOERROR",
    "record_count": 8,
    "dnssec_enabled": true,
    "dnssec_validated": true,
    "min_ttl": 300,
    "max_ttl": 86400
  }
}

Top-level fields

Field Type Description
domain string Domain being monitored
tld string Top-level domain (e.g. com, org)
current object Current DNS snapshot
previous object Previous DNS snapshot
changed_records list Records that changed in this event
metadata object Query metadata

current / previous structure

Both current.dns and previous.dns are maps keyed by domain name, then record name (@ for the apex), then record type. Each entry has values (list of strings) and ttl (int).

current.dns["example.com"]["@"]["A"].values.size()
current.dns["example.com"]["www"]["CNAME"].values[0]
previous.dns["example.com"]["@"]["NS"].values != current.dns["example.com"]["@"]["NS"].values

changed_records fields

Field Type Description
name string Record name (@ for apex, www for www, etc.)
type string Record type: A, AAAA, MX, NS, TXT, CNAME, CAA, SOA, SRV, PTR
action string added, modified, or deleted
old_values list Previous record values
new_values list New record values
old_ttl int Previous TTL in seconds
new_ttl int New TTL in seconds
dnssec_status string validated, failed, or unsigned

metadata fields

Field Type Description
fetched_at string ISO 8601 timestamp when the check ran
nameserver string DNS resolver used for the query
response_time_ms int Query response time in milliseconds
query_status string DNS response code: NOERROR, NXDOMAIN, SERVFAIL, etc.
record_count int Total number of records in the snapshot
dnssec_enabled bool Whether DNSSEC is configured for the domain
dnssec_validated bool Whether DNSSEC validation passed
min_ttl int Lowest TTL across all records (seconds)
max_ttl int Highest TTL across all records (seconds)

Example rules

Any A record changed:

changed_records.exists(r, r.type == "A")

Nameserver changed:

changed_records.exists(r, r.type == "NS")

MX record added (new mail provider):

changed_records.exists(r, r.type == "MX" && r.action == "added")

SPF record modified:

changed_records.exists(r, r.type == "TXT" && r.old_values.exists(v, v.startsWith("v=spf1")) && r.new_values.exists(v, v.startsWith("v=spf1")))

CAA records removed (security concern):

changed_records.exists(r, r.type == "CAA" && r.action == "deleted")

Nameserver pointing to parking service:

changed_records.exists(r, r.type == "NS" && r.new_values.exists(ns, ns.contains("parking") || ns.contains("sedo")))

Multiple records changed simultaneously:

changed_records.size() >= 3

DNSSEC validation failed:

metadata.dnssec_enabled && !metadata.dnssec_validated

TTL dropped below 5 minutes:

changed_records.exists(r, r.new_ttl < 300 && r.new_ttl != r.old_ttl)

DNS query returned error:

metadata.query_status != "NOERROR"


API reference

All DNS Monitoring endpoints require authentication. See Authentication.

GET /api/dns-watcher/domains

List your organization's monitored domains.

Permission: view_domains

Query parameters: page (int, default 1), page_size (int, default 20)

Response:

{
  "domains": [
    {
      "id": 1,
      "domain_name": "example.com",
      "enabled": true,
      "auto_discover": true,
      "notes": "Primary domain",
      "last_checked_at": "2026-01-15T10:00:00Z",
      "last_check_status": "success",
      "created_at": "2026-01-01T00:00:00Z"
    }
  ],
  "total": 1,
  "page": 1,
  "page_size": 20
}

POST /api/dns-watcher/domains

Add a domain to DNS monitoring.

Permission: create_domains

Body:

Field Type Required Description
domain_name string Yes Fully-qualified domain name
auto_discover bool No Default true
enabled bool No Default true
notes string No

Response: {"id": 1, "message": "Domain added to monitoring", "quota_remaining": 9}

PATCH /api/dns-watcher/domains/{monitor_id}

Update domain monitor settings (notes, enabled state, auto-discover).

Permission: update_domains

Response: {"message": "Domain monitor updated"}

DELETE /api/dns-watcher/domains/{monitor_id}

Remove a domain from DNS monitoring.

Permission: delete_domains

Response: {"message": "Domain removed from monitoring"}

GET /api/dns-watcher/domains/{domain_id}/records

List all monitored DNS records for a domain.

Permission: view_records

Response:

{
  "records": [
    {
      "id": 10,
      "record_name": "@",
      "record_type": "A",
      "enabled": true,
      "discovered_by": "heuristic",
      "created_at": "2026-01-01T00:00:00Z"
    }
  ],
  "total": 5
}

POST /api/dns-watcher/domains/{domain_id}/records

Add a DNS record to monitor.

Permission: create_records

Body:

Field Type Required Description
record_name string Yes Record name, e.g. @, www, mail
record_type string Yes One of: A, AAAA, MX, NS, TXT, CNAME, CAA, SOA, SRV, PTR

Response: {"id": 11, "record_name": "www", "record_type": "A", "message": "DNS record added to monitoring"}

PATCH /api/dns-watcher/records/{record_id}

Enable or disable a DNS record.

Permission: update_records

Body: {"enabled": false}

Response: {"message": "DNS record updated"}

DELETE /api/dns-watcher/records/{record_id}

Remove a DNS record from monitoring.

Permission: delete_records

Response: {"message": "DNS record removed from monitoring"}

GET /api/dns-watcher/domains/{domain_name}/history

Retrieve the snapshot history for a domain.

Permission: view_history

Query parameters: limit (int, default 30)

Response:

{
  "domain": "example.com",
  "snapshots": [
    {
      "id": "...",
      "timestamp": "2026-01-15T10:00:00Z",
      "changed": true,
      "change_summary": ["A record @ modified"]
    }
  ],
  "total": 12
}

GET /api/dns-watcher/introspection

Returns the CEL variable schema for this module, used by the rule editor's Available fields dropdown.

Permission: module access (any role)