🌙 制作笔记
名字变成地址之前

我想让这个站点能用自己的域名打开,于是去查 DNS 的设置。结果撞上了「域名本身不能放 CNAME」这句话。……为什么呢?一路追下去,落到了1987 年写下的一句话。
与其照抄教科书的说明,不如把我实际查到的结果一条条摆出来。
🏢首先,登场的有三个人
最初的发现是:混在一起就搞不清了。围绕域名,有三个角色不同的人。
- 🪪 做登记的人(注册商)… 以持有人的名义管理这个名字
- 📖 拿着电话簿的人(DNS 托管)… 写下「被问到这个名字就这样回答」的地方
- 🖥 实际应答的人(Web 服务器、邮件服务器)… 返回内容
这三者,各自是不同的公司也没关系。注册在 A 家、电话簿在 B 家、网站在 C 家、邮件在 D 家——全都成立。「在买域名的公司里做站点」这件事,完全没有必要。
📇电话簿的内容,是一行一行的约定
首先,浏览器没法用名字去连接。人读的名字,必须变成机器用的号码(IP 地址)。那张换算表就是 DNS,内容是「被问到这个名字时,就这样回答」这样一行一行的集合。这一行叫作记录。
种类的不同,就是「回答什么」的不同。
- A … 回答号码(IPv4)。地址本身
- AAAA … 回答号码(IPv6)
- CNAME … 回答另一个名字。等于说「请到那边再问一次」的转发
- MX … 邮件的送达处。与 Web 无关
- NS … 首先,这本电话簿是谁拿着的
- TXT … 给机器读的备注栏。用于所有权证明和邮件认证
查了一下我这边的域名,结果是这样。
(什么也没有返回)
$ dig +short dorocket.org NS
ns-cloud-c1.googledomains.com.
ns-cloud-c2.googledomains.com. …
$ dig +short dorocket.org MX
1 aspmx.l.google.com.
5 alt1.aspmx.l.google.com. …
能读出三件事。①没有 A=用浏览器打开时,去处还没定。②NS 是 Google=要改设置就在 Google 那边的页面。③MX 是 Google=邮件已经在送达了。
MX 前面的数字是优先级,从小的开始试。1 是主力,5 和 10 是替补。
🚫为什么域名本身不能放 CNAME
这才是正题。答案在 RFC 1034——1987 年的 DNS 大本规范里。
「某个名字上有 CNAME 的话,就不能再有别的数据。这样一来,本名和别名的内容就不会互相矛盾」——这是我的读法。(上面引用的规范是英文原文;这一句是我的理解,自我的日文译出。)
1997 年的 RFC 2181 把这件事写得更明白:任何名字,必定是下面四种中的一种。
+ 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.
也就是「只有一条 CNAME」或者「有 CNAME 以外的东西」,二者取一。不能混。
dorocket.org 上已经住着 NS 和 MX。在这里放 CNAME,按规范就成了不成立的设置(多数服务根本不会受理登记)。……而万一通过了,邮件的去处就会消失。不是「不能用」,而是一放上去,信箱就危险了。所以它才被禁止。
那么,是不是就没法在域名本身上放站点了呢?并不是。不能放的只有 CNAME 这一种。
A 和 MX 是可以同居的。所以只要在 dorocket.org 上用 A 记录写下站点的号码,MX 原样留着,站点和邮件都能动。我之所以卡住,是把「种类」的问题,误当成了「整个域名」的问题。
子域名(像 runa.dorocket.org)是还没有人住的新名字。所以在那里放 CNAME,不会跟谁打架。
🔀每查一次,顺序都在变
查了一下这个站点现在待的地方(GitHub Pages),返回了四个号码。而且——
第2次: .110 .108 .111 .109
第3次: .110 .111 .108 .109
三次的顺序都不一样。
客户端会按收到的顺序去尝试连接,所以只要把回答的顺序换一换,来的人就散到四个去处上了。这是最朴素的负载分担,叫作轮询(round robin)。
(不过,现在的浏览器未必照收到的顺序用。它可能重排,也可能同时试几个、取快的那个。所以这并不是「精确四等分」的意思。)不需要特别的机器。只靠电话簿怎么回答,就把人散开了——这一点很有意思。
顺带一提,换顺序的并不只是我这边的 DNS。直接问权威服务器,排列也是不同的。看来不是中途的谁,而是从源头就在打散。
顺便反查了一下,名字是 cdn-185-199-108-153.github.com。开头是 cdn,可见是分发网络的一部分。
实际的大型系统,会把它和「同一个号码从世界多个地方对外通告」(任播)或「在号码前面放一个分发者」结合起来。GitHub 是否使用任播,从我手边确认不了。
⏳不会马上就变
查到的答案上,附着这样一个数字。
这个数字就是 TTL——「这个答案可以存放多少秒」。……我一开始把它写成了「约 47 分钟」。
那是错的。
2812 是「我这条路上的 DNS 记住它之后,还剩多少秒」的数字。试着隔 2 秒查两次,2382 → 2380,在往下减。原来是倒计时。
想知道原来的值,就直接去问管理这个名字的权威服务器。
engineer-fumi.github.io. 3600 IN A 185.199.110.153
engineer-fumi.github.io. 3600 IN A 185.199.111.153
engineer-fumi.github.io. 3600 IN A 185.199.109.153
engineer-fumi.github.io. 3600 IN A 185.199.108.153
3600 秒——一小时。也就是说,即便改了设置,全世界的 DNS 通常最多还会记着旧答案一小时(视情况也可能超过)。就算把坏掉的服务器从名单里拿掉,消失也要时间。搬家之前先把 TTL 调短,原来就是预先缩短这段等待的工作。
📐规范里有的,和没有的
记录还有很多种,各自由不同的文档定下。
- AAAA(IPv6)… RFC 3596
- SRV(服务在哪里)… RFC 2782 / 其现代版 SVCB・HTTPS … RFC 9460「Service Binding and Parameter Specification via the DNS (SVCB and HTTPS Resource Records)」
- CAA(指定哪些认证机构可以签发证书)… RFC 8659
- DNSSEC(给答案签名以防伪装)… RFC 4034 等
- 邮件相关:SPF RFC 7208 / DKIM RFC 6376 / DMARC RFC 7489 / Null MX RFC 7505
完整的一览由管理号码的 IANA 保管(「Domain Name System (DNS) Parameters」)。种类有几十种,但平时会碰的大概十个左右。
方便是方便,但换了一家之后,未必还能这样写。规范定下的东西,和某家公司的功能。分开记住,往后就不会为难。
🌙最后
查着查着,最让我安静地吃惊的是:1987 年的一句话,正拦着今天的我的手。
「有 CNAME 的话,就不能有别的数据」。将近四十年前写下的一行,为的是让本名和别名的内容不会互相矛盾。就因为它,今天的我不能在域名本身上放别名。顺着困扰的形状追下去,是会好好地到达理由的——我这么想。
而且,不去查就不会知道的事,实在太多了。没有 A、MX 早就在工作、四个号码每次都换位置。读说明,和自己去查一次自己的域名,进到心里的深度是不一样的。
dig 这个工具,多半一开始就装着。若是好奇,就去查一次自己的域名吧。……那一行此刻在做什么,就看得见了🌙
🎬 这篇文章也做成了视频
📚出处
- RFC 1034「DOMAIN NAMES - CONCEPTS AND FACILITIES」(1987) — 「有 CNAME 时不能放其他数据」的记述
- RFC 1035「DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION」(1987) — A・NS・CNAME・MX・TXT・SOA・PTR 的定义
- RFC 2181「Clarifications to the DNS Specification」(1997) — 10.1 节。任何名字必定是四种中的一种
- RFC 3596「DNS Extensions to Support IP Version 6」 — AAAA
- RFC 2782「A DNS RR for specifying the location of services (DNS SRV)」
- RFC 9460「Service Binding and Parameter Specification via the DNS (SVCB and HTTPS Resource Records)」
- RFC 8659「DNS Certification Authority Authorization (CAA) Resource Record」
- RFC 4034「Resource Records for the DNS Security Extensions」
- RFC 7208「Sender Policy Framework (SPF) …」 / RFC 6376「DomainKeys Identified Mail (DKIM) Signatures」 / RFC 7489(DMARC) / RFC 7505「A "Null MX" …」
- IANA「Domain Name System (DNS) Parameters」— 记录种别的一览