Why can't a CNAME record be used at the apex (aka root) of a domain?

Solution 1:

CNAME records were originally created to allow multiple names that provide the same resource to be aliased to a single "canonical name" for the resource. With the advent of name based virtual hosting, it has instead become commonplace to use them as a generic form of IP address aliasing. Unfortunately, most people who come from a web hosting background expect CNAME records to indicate equivalence in the DNS, which has never been the intent. The apex contains record types which are clearly not used in the identification of a canonical host resource (NS, SOA), which cannot be aliased without breaking the standard at a fundamental level. (particularly in regards to zone cuts)

Unfortunately, the original DNS standard was written before the standards governing bodies realized that explicit verbiage was necessary to define consistent behavior (RFC 2119). It was necessary to create RFC 2181 to clarify several corner cases due to vague wording, and the updated verbiage makes it clearer that a CNAME cannot be used to achieve apex aliasing without breaking the standard.

6.1. Zone authority

The authoritative servers for a zone are enumerated in the NS records for the origin of the zone, which, along with a Start of Authority (SOA) record are the mandatory records in every zone. Such a server is authoritative for all resource records in a zone that are not in another zone. The NS records that indicate a zone cut are the property of the child zone created, as are any other records for the origin of that child zone, or any sub-domains of it. A server for a zone should not return authoritative answers for queries related to names in another zone, which includes the NS, and perhaps A, records at a zone cut, unless it also happens to be a server for the other zone.

This establishes that SOA and NS records are mandatory, but it says nothing about A or other types appearing here. It may seem superfluous that I quote this then, but it will become more relevant in a moment.

RFC 1034 was somewhat vague about the problems that can arise when a CNAME exists alongside other record types. RFC 2181 removes the ambiguity and explicitly states the record types that are allowed to exist alongside them:

10.1. CNAME resource records

The DNS CNAME ("canonical name") record exists to provide the canonical name associated with an alias name. There may be only one such canonical name for any one alias. That name should generally be a name that exists elsewhere in the DNS, though there are some rare applications for aliases with the accompanying canonical name undefined in the DNS. An alias name (label of a CNAME record) may, if DNSSEC is in use, have SIG, NXT, and KEY RRs, but may have no other data. That is, for any label in the DNS (any domain name) exactly one of the following is true:

  • one CNAME record exists, optionally accompanied by SIG, NXT, and KEY RRs,
  • one or more records exist, none being CNAME records,
  • the name exists, but has no associated RRs of any type,
  • the name does not exist at all.

"alias name" in this context is referring to the left hand side of the CNAME record. The bulleted list makes it explicitly clear that a SOA, NS, and A records cannot be seen at a node where a CNAME also appears. When we combine this with section 6.1, it is impossible for a CNAME to exist at the apex as it would have to live alongside mandatory SOA and NS records.

(This seems to do the job, but if someone has a shorter path to proof please give a crack at it.)


Update:

It seems that the more recent confusion is coming from Cloudflare's recent decision to allow an illegal CNAME record to be defined at the apex of domains, for which they will synthesize A records. "RFC compliant" as described by the linked article refers to the fact that the records synthesized by Cloudflare will play nicely with DNS. This does not change the fact that it is a completely custom behavior.

In my opinion this is a disservice to the larger DNS community: it is not in fact a CNAME record, and it misleads people into believing that other software is deficient for not allowing it. (as my question demonstrates)

Solution 2:

The Internet Systems Consortium recently posted a write-up on CNAME at the apex of a zone, why this restriction exists, and a number of alternatives. This is not likely to change anytime soon, sadly:

We cannot change how the special CNAME record is used without changing all of the >DNS server implementations in the world at the same time. This is because its meaning and interpretation was strictly defined in the DNS protocol; all current DNS client and server implementations adhere to this specification. Attempting to ‘relax’ how CNAME is used in authoritative servers without simultaneously changing all DNS resolvers currently in operation will cause name resolution to break (and web and email services to become intermittently unavailable for those organizations implementing ‘relaxed’ authoritative server solutions.

But there's hope:

Another potential solution currently being discussed would add a new dns resource record type that browsers would look up, that could exist at the apex. This would be an application-specific hostname for http requests (similar to the way MX works).

Pros: This is completely consistent with the DNS design.
Cons: This is not available yet, and would require a browser client update.

Solution 3:

If you are redirecting an entire zone, you should use DNAME. According to RFC 6672,

The DNAME RR and the CNAME RR [RFC1034] cause a lookup to (potentially) return data corresponding to a domain name different from the queried domain name. The difference between the two resource records is that the CNAME RR directs the lookup of data at its owner to another single name, whereas a DNAME RR directs lookups for data at descendants of its owner's name to corresponding names under a different (single) node of the tree.

For example, take looking through a zone (see RFC 1034 [RFC1034], Section 4.3.2, step 3) for the domain name "foo.example.com", and a DNAME resource record is found at "example.com" indicating that all queries under "example.com" be directed to "example.net". The lookup process will return to step 1 with the new query name of "foo.example.net". Had the query name been "www.foo.example.com", the new query name would be "www.foo.example.net".