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

Steps

  1. Step 1.

    Ask for the CNAME type by name.

    nslookup -type=CNAME www.github.com 8.8.8.8
    
    Non-authoritative answer:
    Server:  dns.google
    Address:  8.8.8.8
    
    www.github.com	canonical name = github.com
  2. 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.8
    
    Non-authoritative answer:
    Server:  dns.google
    Address:  8.8.8.8
    
    Name:    github.com
    Address:  140.82.121.3
    Aliases:  www.github.com

    The name that was queried has moved to the bottom line, and the top line names a domain that was never typed.

  3. Step 3.

    Run both queries from Node, where the alias disappears from the address answer entirely. Save it as cname.js and run node 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 60

    resolve4 reports an address and no alias. Nothing in that line says the name is a CNAME.

  4. Step 4.

    Ask for a CNAME at the registrable domain, where one cannot exist.

    nslookup -type=CNAME github.com 8.8.8.8
    
    Server:  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.

  5. 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.js and run node 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.com

    The 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.

  6. 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.org
    
    CNAME 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 2

    Four 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

Sign: An A lookup of an aliased name looks like a direct address record, so the report says no CNAME is present.Cause: A resolver answers an A query at an aliased name with the CNAME and the resolved address together. Windows nslookup prints the target on the Name: line and the queried name under Aliases:, and Node's resolve4 drops the alias completely. Only an explicit CNAME query shows the record.
Sign: A verification TXT record or an MX is added at a name that already has a CNAME, and the provider never sees it.Cause: A CNAME cannot coexist with other data at the same name. The resolver answers those queries by following the alias and returning the target's records, as step 5 shows, so the new record is unreachable however correct it looks in the zone editor.
Sign: The zone editor refuses a CNAME at the registrable domain and the ticket is filed against the editor.Cause: The apex already holds NS and SOA records, which every zone must have, and the coexistence rule forbids a CNAME beside them. Providers that appear to allow it are synthesising A records at answer time, which is not a CNAME and does not behave like one.
Sign: A test resolves an aliased name once at start-up, pins the address, and fails minutes later against a name that still resolves.Cause: The alias and the addresses behind it are cached on different clocks. In step 6 the CDN addresses carried a TTL of 2 seconds while the alias itself is the stable part of the answer. An address pinned from one lookup can be withdrawn while the CNAME stays correct.

What to check next

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.

basic5 minpublished updated Maks Verny