dns.enhost.uk
dns.enhost.uk is a free DNS lookup tool for checking DNS records of any domain. Query A, AAAA, MX, TXT, NS, CNAME, and other record types. Each lookup queries 38 public DNS servers around the world - over DNS-over-HTTPS where available, otherwise plain DNS (Do53) to the server's IP - plots them on the map above, and compares the results to highlight discrepancies. Useful for spotting DNS propagation issues and regional filtering.
enhost's own servers (
)
come first, followed by the major public resolvers; the remaining ones are collapsed
behind the show-all toggle and queried when you expand it. Each server shows how it was
queried:
DoH (DNS-over-HTTPS, preferred) or
Do53 (plain DNS to the server's IP on port 53).
Anycast networks answer from the node nearest to this server, so map positions for anycast resolvers show the operator's home region, not necessarily where the query landed.
Authoritative DNS Servers:
Every lookup that is not already cached starts at the root. There are thirteen root server names,
a through m, and the reason is a packet size: a DNS response had to fit in
512 bytes of UDP (RFC 1035), and thirteen nameserver records plus their addresses was the most that
would fit. EDNS(0) lifted that limit in 1999, but the thirteen names are permanent now.
Thirteen names is not thirteen machines. Every letter is an anycast cloud of hundreds of instances worldwide, so those thirteen addresses are answered by well over a thousand servers.
| Name | Operator | IPv4 | IPv6 |
|---|---|---|---|
| a.root-servers.net | Verisign | 198.41.0.4 | 2001:503:ba3e::2:30 |
| b.root-servers.net | USC Information Sciences Institute | 170.247.170.2 | 2801:1b8:10::b |
| c.root-servers.net | Cogent Communications | 192.33.4.12 | 2001:500:2::c |
| d.root-servers.net | University of Maryland | 199.7.91.13 | 2001:500:2d::d |
| e.root-servers.net | NASA Ames Research Center | 192.203.230.10 | 2001:500:a8::e |
| f.root-servers.net | Internet Systems Consortium | 192.5.5.241 | 2001:500:2f::f |
| g.root-servers.net | US Department of Defense (NIC) | 192.112.36.4 | 2001:500:12::d0d |
| h.root-servers.net | US Army Research Lab | 198.97.190.53 | 2001:500:1::53 |
| i.root-servers.net | Netnod | 192.36.148.17 | 2001:7fe::53 |
| j.root-servers.net | Verisign | 192.58.128.30 | 2001:503:c27::2:30 |
| k.root-servers.net | RIPE NCC | 193.0.14.129 | 2001:7fd::1 |
| l.root-servers.net | ICANN | 199.7.83.42 | 2001:500:9f::42 |
| m.root-servers.net | WIDE Project | 202.12.27.33 | 2001:dc3::35 |
The IETF has reserved these from ever being delegated, so they are safe to use privately and
guaranteed never to collide with a real domain. .test is why Herd and Valet can hand
you dns.test without asking anyone's permission.
| Name | Reserved by | Why |
|---|---|---|
| .test | RFC 6761 | Reserved for testing. Never delegated, so it is safe to use for local development -- which is exactly what Herd and Valet do. |
| .localhost | RFC 6761 | Must always resolve to the loopback address. Resolvers are expected to answer it without asking anyone. |
| .invalid | RFC 6761 | Reserved to be obviously invalid. Guaranteed never to resolve. |
| .example | RFC 6761 | Reserved for documentation, along with example.com, example.net and example.org. |
| example.com | RFC 2606 | Reserved for documentation, with example.net and example.org. Delegated to IANA, which serves a placeholder page. |
| example.net | RFC 2606 | Reserved for documentation, with example.com and example.org. |
| example.org | RFC 2606 | Reserved for documentation, with example.com and example.net. |
| home.arpa | RFC 8375 | The standard name for home networks, chosen after .home was proposed and rejected. |
| .onion | RFC 7686 | Tor hidden services. Reserved so that ordinary resolvers do not leak the lookup. |
| .local | RFC 6762 | Multicast DNS. Resolved by asking the local network rather than the DNS hierarchy. |
| .alt | RFC 9476 | Reserved for non-DNS naming systems, so they stop squatting on real TLDs. |
| .internal | ICANN reserved, 2024 | Set aside by ICANN for private internal networks and never to be delegated. |
Query DNS records via HTTP API:
https://dns.enhost.uk/?domain=example.com&type=A
Parameters:
• domain - Domain name to query (required). For PTR lookups an IP address is accepted and converted to its reverse name automatically
• type - Record type: A, AAAA, CNAME, MX, TXT, NS, SOA, CAA, SRV, PTR, HTTPS, SVCB, DS, DNSKEY, TLSA, NAPTR (default: A)
• server - Query a single server by ID, e.g. server=google. Without this parameter, enhost's own servers are queried
List available servers (name, endpoints, coordinates, organisation):
https://dns.enhost.uk/?servers=1
Each result includes a protocol
field showing how the server was reached: doh
(DNS-over-HTTPS, preferred) or do53
(plain DNS to the server's IP).
Example response:
{
"domain": "example.com",
"type": "A",
"results": {
"enhost-uk": {
"name": "ns.enhostdns.uk",
"org": "enhost",
"location": "GB",
"lat": 51.5,
"lng": -0.1,
"protocol": "doh",
"result": {
"Status": 0,
"Answer": [
{
"name": "example.com.",
"type": 1,
"TTL": 3600,
"data": "93.184.216.34",
"enhost": false
}
]
}
},
...
}
}
Every answer record carries enhost, true when the value points at enhost
infrastructure — an A/AAAA address of ours, or an NS, CNAME, PTR or MX target on our
nameservers. Addresses that name a specific service also carry
enhost_label, for example "App Hosting LB".
Using cURL (all servers):
curl "https://dns.enhost.uk/?domain=enhost.uk&type=A"
Query a single server:
curl "https://dns.enhost.uk/?domain=enhost.uk&type=A&server=cloudflare"
List available servers:
curl "https://dns.enhost.uk/?servers=1"
Extract records with jq:
curl -s "https://dns.enhost.uk/?domain=enhost.uk&type=A" | jq -r '.results[].result.Answer[]?.data' | sort -u
Bash script example:
#!/bin/bash
DOMAIN="enhost.uk"
TYPE="A"
# Query DNS across all servers
RESULT=$(curl -s "https://dns.enhost.uk/?domain=$DOMAIN&type=$TYPE")
# Show what each server returned and how it was reached
echo "$RESULT" | jq -r '.results | to_entries[] |
"\(.value.name) [\(.value.protocol)]: \(.value.result.Answer[]?.data // "no records")"'
Python example:
import requests
domain = "enhost.uk"
record_type = "A"
response = requests.get(
"https://dns.enhost.uk/",
params={"domain": domain, "type": record_type}
)
data = response.json()
for server_id, server in data["results"].items():
result = server["result"]
if "Answer" in result:
records = ", ".join(r["data"] for r in result["Answer"])
else:
records = result.get("error", "no records")
print(f"{server['name']} ({server['protocol']}): {records}")
JavaScript example:
const domain = 'enhost.uk';
const recordType = 'A';
fetch(`https://dns.enhost.uk/?domain=${domain}&type=${recordType}`)
.then(res => res.json())
.then(data => {
for (const [id, server] of Object.entries(data.results)) {
const records = server.result.Answer
? server.result.Answer.map(r => r.data).join(', ')
: (server.result.error || 'no records');
console.log(`${server.name} [${server.protocol}]: ${records}`);
}
});
PHP example:
<?php
$domain = 'enhost.uk';
$type = 'A';
$url = "https://dns.enhost.uk/?domain=" . urlencode($domain) .
"&type=" . urlencode($type);
$response = file_get_contents($url);
$data = json_decode($response, true);
foreach ($data['results'] as $id => $server) {
$records = isset($server['result']['Answer'])
? implode(', ', array_column($server['result']['Answer'], 'data'))
: ($server['result']['error'] ?? 'no records');
echo "{$server['name']} [{$server['protocol']}]: $records\n";
}
?>