DNS Check Configuration Examples¶
This document provides example configurations for DNS monitoring checks in nyxmon.
Configuration Structure¶
DNS checks use the following structure in the check.data field:
{
"expected_ips": ["192.168.178.94"], # Required: List of expected IP addresses
"dns_server": "192.168.178.94", # Optional: DNS server to query (uses system default if not specified)
"source_ip": "192.168.178.50", # Optional: Source IP to bind for the query (not interface name)
"query_type": "A", # Optional: Record type (default: "A")
"timeout": 5.0 # Optional: Query timeout in seconds (default: 5.0)
}
Tip
Prefer the NyxBoard UI? The easiest way to create DNS checks is through the web dashboard. See Usage → Creating Checks via the Dashboard for a visual guide to the DNS check form. The UI handles JSON structure automatically.
Example Configurations¶
Basic DNS Check¶
Query the default system DNS resolver to check if a domain resolves to expected IP:
from nyxmon.domain import Check, CheckType
check = Check(
check_id=1,
name="Basic DNS - example.com",
check_type=CheckType.DNS,
url="example.com",
data={
"expected_ips": ["93.184.216.34"]
},
interval=300
)
LAN DNS Check (Split-Horizon DNS)¶
Check that a domain resolves to the internal LAN IP when queried from a LAN interface:
check = Check(
check_id=2,
name="DNS - home.wersdoerfer.de from LAN",
check_type=CheckType.DNS,
url="home.xn--wersdrfer-47a.de",
data={
"expected_ips": ["192.168.178.94"],
"dns_server": "192.168.178.94",
"source_ip": "192.168.178.50", # Must be actual LAN IP of monitoring host
"query_type": "A"
},
interval=60
)
Important: source_ip must be an actual IP address assigned to the monitoring host’s LAN interface, not the interface name (e.g., not “eth0” or “en0”).
Tailscale DNS Check (Split-Horizon DNS)¶
Check that a domain resolves to the Tailscale IP when queried from a Tailscale interface:
check = Check(
check_id=3,
name="DNS - home.wersdoerfer.de from Tailscale",
check_type=CheckType.DNS,
url="home.xn--wersdrfer-47a.de",
data={
"expected_ips": ["100.119.21.93"],
"dns_server": "100.119.21.93",
"source_ip": "100.119.21.50", # Must be actual Tailscale IP of monitoring host
"query_type": "A"
},
interval=60
)
Custom DNS Server¶
Query a specific DNS server (e.g., Google DNS, Cloudflare DNS):
# Google DNS
check = Check(
check_id=4,
name="DNS via Google DNS - example.com",
check_type=CheckType.DNS,
url="example.com",
data={
"expected_ips": ["93.184.216.34"],
"dns_server": "8.8.8.8"
},
interval=300
)
# Cloudflare DNS
check = Check(
check_id=5,
name="DNS via Cloudflare - example.com",
check_type=CheckType.DNS,
url="example.com",
data={
"expected_ips": ["93.184.216.34"],
"dns_server": "1.1.1.1"
},
interval=300
)
Multiple Expected IPs¶
Check that DNS returns one of several acceptable IP addresses:
check = Check(
check_id=6,
name="DNS - CDN with multiple IPs",
check_type=CheckType.DNS,
url="cdn.example.com",
data={
"expected_ips": [
"192.0.2.1",
"192.0.2.2",
"192.0.2.3"
]
},
interval=300
)
The check will succeed if the DNS response contains any of the expected IPs.
Custom Timeout¶
Set a custom timeout for DNS queries (useful for slow DNS servers):
check = Check(
check_id=7,
name="DNS with custom timeout",
check_type=CheckType.DNS,
url="slow-dns.example.com",
data={
"expected_ips": ["192.0.2.1"],
"timeout": 10.0 # 10 second timeout
},
interval=300
)
AAAA (IPv6) Record Check¶
Check IPv6 addresses:
check = Check(
check_id=8,
name="DNS - IPv6 check",
check_type=CheckType.DNS,
url="example.com",
data={
"expected_ips": ["2606:2800:220:1:248:1893:25c8:1946"],
"query_type": "AAAA"
},
interval=300
)
Using the CLI¶
You can add DNS checks using the add-check CLI tool:
# Add a basic DNS check
uv run add-check \
--name "DNS - example.com" \
--check-type dns \
--url "example.com" \
--interval 300 \
--data '{"expected_ips": ["93.184.216.34"]}'
# Add a split-horizon DNS check for LAN
uv run add-check \
--name "DNS - home from LAN" \
--check-type dns \
--url "home.xn--wersdrfer-47a.de" \
--interval 60 \
--data '{
"expected_ips": ["192.168.178.94"],
"dns_server": "192.168.178.94",
"source_ip": "192.168.178.50"
}'
Result Data Structure¶
Success Result¶
When a DNS check succeeds, the result includes:
{
"resolved_ips": ["192.168.178.94"],
"query_time_ms": 23,
"response_code": "NOERROR",
"questions": ["home.xn--wersdrfer-47a.de. IN A"],
"rrset": ["192.168.178.94"],
"dns_server": "192.168.178.94",
"source_address": "192.168.178.50" # Only if source_ip was specified
}
Failure Result (Resolution Mismatch)¶
When resolved IPs don’t match expected:
{
"error_type": "resolution_mismatch",
"expected": ["192.168.178.94"],
"actual": ["192.168.178.95"],
"query_time_ms": 45,
"response_code": "NOERROR",
"questions": ["home.xn--wersdrfer-47a.de. IN A"],
"rrset": ["192.168.178.95"],
"dns_server": "192.168.178.94"
}
Failure Result (DNS Error)¶
When DNS query fails:
{
"error_type": "nxdomain", # or "timeout", "no_answer", etc.
"error_msg": "Domain example.invalid does not exist"
}
Finding Your Source IP¶
To find the appropriate source_ip for your checks:
# List all network interfaces and their IPs
ip addr show # Linux
ifconfig # macOS/BSD
# Find your LAN IP (typically 192.168.x.x or 10.x.x.x)
ip addr show eth0 # Linux - replace eth0 with your interface
# Find your Tailscale IP (typically 100.x.x.x)
tailscale ip
Use the IP address shown, not the interface name (e.g., “192.168.178.50”, not “eth0”).
Supported Query Types¶
The following DNS record types are supported via the query_type field:
A: IPv4 address (default)
AAAA: IPv6 address
MX: Mail exchange records
TXT: Text records
CNAME: Canonical name
NS: Name server
SOA: Start of authority
PTR: Pointer (reverse DNS)
Best Practices¶
Split-Horizon DNS: Create separate checks for each network context (LAN, VPN, public)
Intervals: Use shorter intervals (60s) for critical internal services, longer (300s) for external
Multiple IPs: List all acceptable IPs when using load balancers or CDNs
Timeouts: Keep timeouts reasonable (5-10s) to avoid blocking other checks
Documentation: Document why specific source IPs are used in check names
Troubleshooting¶
“Source IP binding failed”¶
Ensure the source IP is actually assigned to the monitoring host
Check that you’re using an IP address, not an interface name
Verify network permissions allow binding to that source
“DNS timeout”¶
Check if the DNS server is reachable
Increase the timeout value
Verify firewall rules allow DNS (UDP/TCP port 53)
“Resolution mismatch”¶
Verify the expected IPs are correct
Check if DNS records have changed
For split-horizon DNS, ensure you’re querying the correct DNS server with the correct source IP