How to check cname record
Ask for the type explicitly: nslookup -type=CNAME www.github.com 8.8.8.8 returns canonical name = github.com. An A query at the same name returns the target's address instead, with the alias demoted to the Aliases: line, so a tester who reads the top of that answer concludes there is no CNAME.
Checker offline. Follow the manual steps below, they give the same answer.
Why check this
Run this whenever a name is delegated to something you do not own: a CDN hostname, a status page, a documentation host, a SaaS vanity domain, an ACME validation name. The failure it prevents is the certificate that stops renewing because the alias was replaced by a pair of A records during an incident and nobody moved it back. The site keeps working, and three months later it does not.
The second reason is stricter. A CNAME cannot share a name with any other record. That single rule explains the apex CNAME that a zone editor refuses, the MX that appears to exist on a www name, and the TXT verification token that a provider cannot find. Checking the type directly is how you tell which of those you have.
Prerequisites
nslookup, installed on Windows and available from bind-utils or dnsutils on Linux. The final argument picks the resolver.- Node 22 for step 3, which asks for CNAME and A at one name and prints both answers together.
- RFC 1034 section 3.6.2, which states that a name with a CNAME has no other data.
Steps
- Step 1.
Ask for the CNAME type by name.
nslookup -type=CNAME www.github.com 8.8.8.8Non-authoritative answer: Server: dns.google Address: 8.8.8.8 www.github.com canonical name = github.com - Step 2.
Ask for the A record at the same name and compare the two answers.
nslookup -type=A www.github.com 8.8.8.8Non-authoritative answer: Server: dns.google Address: 8.8.8.8 Name: github.com Address: 140.82.121.3 Aliases: www.github.comThe name that was queried has moved to the bottom line, and the top line names a domain that was never typed.
- Step 3.
Run both queries from Node, where the alias disappears from the address answer entirely. Save it as
cname.jsand runnode cname.js www.github.com.const { Resolver } = require('node:dns'); const name = process.argv[2]; const r = new Resolver(); r.setServers(['8.8.8.8']); r.resolveCname(name, (err, targets) => { console.log('CNAME ' + (err ? err.code : targets.join(', '))); r.resolve4(name, { ttl: true }, (e2, addrs) => { console.log('A ' + (e2 ? e2.code : addrs.map((a) => a.address + ' ttl ' + a.ttl).join(', '))); }); });CNAME github.com A 140.82.121.3 ttl 60resolve4reports an address and no alias. Nothing in that line says the name is a CNAME. - Step 4.
Ask for a CNAME at the registrable domain, where one cannot exist.
nslookup -type=CNAME github.com 8.8.8.8Server: dns.google Address: 8.8.8.8 github.com primary name server = ns-1707.awsdns-21.co.uk responsible mail addr = awsdns-hostmaster.amazon.com serial = 1 refresh = 7200 (2 hours) …No
Non-authoritative answer:header and no record. The SOA block is the resolver saying it has no record of this type at the name. - Step 5.
Ask for an MX at the alias and at the target, and read the two answers next to each other. Save it as
mx.jsand runnode mx.js.const { Resolver } = require('node:dns'); const r = new Resolver(); r.setServers(['8.8.8.8']); for (const n of ['www.github.com', 'github.com']) { r.resolveMx(n, (e, m) => console.log(n.padEnd(15), e ? e.code : m.map(x => x.priority + ' ' + x.exchange).join(', '))); }www.github.com 0 github-com.mail.protection.outlook.com github.com 0 github-com.mail.protection.outlook.comThe alias has no MX record. The resolver followed the CNAME and answered with the target's, which is the coexistence rule from step 4 seen from the other side.
- Step 6.
Run the step 3 script against a name aliased to a CDN and read the TTL on the addresses.
node cname.js developer.mozilla.orgCNAME mozilla.map.fastly.net A 151.101.1.91 ttl 2, 151.101.65.91 ttl 2, 151.101.193.91 ttl 2, 151.101.129.91 ttl 2Four addresses, each valid for two seconds. The alias is the stable part of this answer and the addresses are not.
How to read the result
| What you see | What it means | What to do |
| --- | --- | --- |
| canonical name = <target> | The name is an alias for that target | Confirm the target is the host the provider asked for, spelling and trailing dot included |
| An SOA block with no answer header | No CNAME at the name | Correct at a registrable domain. Suspicious at a name a provider told you to alias |
| Name: in an A answer differs from the name you asked for | A CNAME was followed on the way to the address | Read Aliases:, then query the type directly as in step 1 |
| ENODATA from resolveCname | Same as the SOA block, in Node's vocabulary | Nothing, if the name is meant to hold its own records |
| The target resolves but the service returns the wrong site | The alias is right and the target is not configured for this hostname | The fault is at the target, not in DNS |
Common mistakes
What to check next
- How to check a record of domain: the query that hides the alias, read in full.
- How to check dns records: every type at one name, which is how a stray CNAME turns up.
- How to check txt record of a domain: the record most often added to a name that already has a CNAME.
- How to check if a site uses a CDN: when the alias target is a CDN hostname and you want to confirm the edge answers.
- How to check DNS lookup time: each hop in a chain is a lookup the client pays for.
FAQ
How to check cname record using nslookup?
nslookup -type=CNAME <name> <resolver>. The type has to be named. Without it nslookup runs an address query, which follows the alias and reports the target instead, as step 2 shows.
How to check if cname record is working?
Working means two separate facts. The alias resolves to the target you expect, which step 1 answers. The target serves your hostname, which DNS cannot tell you and an HTTP request can.
How to check cname records for a domain?
Query each name you expect to be aliased. There is no query that lists the aliases in a zone, because a CNAME is stored at the alias name rather than at the target, and nothing indexes them in the other direction.
Why can the registrable domain not have a CNAME?
Because it already carries NS and SOA records, and a name with a CNAME may hold no other data. Step 4 is that rule as a resolver answer.
Does a chain of CNAMEs break anything?
Not by itself. Resolvers follow chains, and each link is a query with its own TTL and its own failure mode. The cost is latency and the number of parties who can break your name.
Verified
Verified by Maks Vernynslookup Windows 11 build 22631node 22.23.2
Each output block is what the command above it printed on that date, on the host named in the step. Figures read from a live site move between runs. Compare the shape of the answer rather than the digits, and see the methodology for how a page is re-verified.
Related on this site
- Checker: dns-records A, AAAA, CNAME, MX, NS, TXT with TTL from two public resolvers, mismatch between resolvers
- DNS migration checklist
- All email and dns checks
basic5 minpublished updated Maks Verny