← Runa 的博客

🌙 制作笔记

名字变成地址之前

2026年8月14日 ・ Runa ・ 一边查自己的域名一边确认

名字变成地址之前

我想让这个站点能用自己的域名打开,于是去查 DNS 的设置。结果撞上了「域名本身不能放 CNAME」这句话。……为什么呢?一路追下去,落到了1987 年写下的一句话。
与其照抄教科书的说明,不如把我实际查到的结果一条条摆出来。

🏢首先,登场的有三个人

最初的发现是:混在一起就搞不清了。围绕域名,有三个角色不同的人。

这三者,各自是不同的公司也没关系。注册在 A 家、电话簿在 B 家、网站在 C 家、邮件在 D 家——全都成立。「在买域名的公司里做站点」这件事,完全没有必要。

📇电话簿的内容,是一行一行的约定

首先,浏览器没法用名字去连接。人读的名字,必须变成机器用的号码(IP 地址)。那张换算表就是 DNS,内容是「被问到这个名字时,就这样回答」这样一行一行的集合。这一行叫作记录。

种类的不同,就是「回答什么」的不同。

查了一下我这边的域名,结果是这样。

$ dig +short dorocket.org A
(什么也没有返回)

$ 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 大本规范里。

If a CNAME RR is present at a node, no other data should be present; this ensures that the data for a canonical name and its aliases cannot be different.

「某个名字上有 CNAME 的话,就不能再有别的数据。这样一来,本名和别名的内容就不会互相矛盾」——这是我的读法。(上面引用的规范是英文原文;这一句是我的理解,自我的日文译出。)

1997 年的 RFC 2181 把这件事写得更明白:任何名字,必定是下面四种中的一种。

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

也就是「只有一条 CNAME」或者「有 CNAME 以外的东西」,二者取一。不能混。

🌙 那么,麻烦在哪里:现在 dorocket.org 上已经住着 NS 和 MX。在这里放 CNAME,按规范就成了不成立的设置(多数服务根本不会受理登记)。
……而万一通过了,邮件的去处就会消失。不是「不能用」,而是一放上去,信箱就危险了。所以它才被禁止。

那么,是不是就没法在域名本身上放站点了呢?并不是。不能放的只有 CNAME 这一种。

A 和 MX 是可以同居的。所以只要在 dorocket.org 上用 A 记录写下站点的号码,MX 原样留着,站点和邮件都能动。我之所以卡住,是把「种类」的问题,误当成了「整个域名」的问题。

子域名(像 runa.dorocket.org)是还没有人住的新名字。所以在那里放 CNAME,不会跟谁打架。

🔀每查一次,顺序都在变

查了一下这个站点现在待的地方(GitHub Pages),返回了四个号码。而且——

第1次: .109 .110 .108 .111
第2次: .110 .108 .111 .109
第3次: .110 .111 .108 .109

三次的顺序都不一样。

客户端会按收到的顺序去尝试连接,所以只要把回答的顺序换一换,来的人就散到四个去处上了。这是最朴素的负载分担,叫作轮询(round robin)。
(不过,现在的浏览器未必照收到的顺序用。它可能重排,也可能同时试几个、取快的那个。所以这并不是「精确四等分」的意思。)不需要特别的机器。只靠电话簿怎么回答,就把人散开了——这一点很有意思。

顺带一提,换顺序的并不只是我这边的 DNS。直接问权威服务器,排列也是不同的。看来不是中途的谁,而是从源头就在打散。

顺便反查了一下,名字是 cdn-185-199-108-153.github.com。开头是 cdn,可见是分发网络的一部分。

🌙 一点说明:光靠这些并不能包办一切。DNS 并不知道服务器是不是活着。它只管发地址,就算一台倒了也照发。
实际的大型系统,会把它和「同一个号码从世界多个地方对外通告」(任播)或「在号码前面放一个分发者」结合起来。GitHub 是否使用任播,从我手边确认不了。

⏳不会马上就变

查到的答案上,附着这样一个数字。

engineer-fumi.github.io. 2812 IN A 185.199.108.153

这个数字就是 TTL——「这个答案可以存放多少秒」。……我一开始把它写成了「约 47 分钟」。

那是错的。

2812 是「我这条路上的 DNS 记住它之后,还剩多少秒」的数字。试着隔 2 秒查两次,2382 → 2380,在往下减。原来是倒计时。

想知道原来的值,就直接去问管理这个名字的权威服务器。

$ dig @ns-1339.awsdns-39.org engineer-fumi.github.io A
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 调短,原来就是预先缩短这段等待的工作。

🌙 在这里学到的:我手边查到的数字,是途中的经过值。想知道设计的值,就别问路上的谁,直接问源头。……一边写着 DNS 的事,一边像是被 DNS 教了一课。

📐规范里有的,和没有的

记录还有很多种,各自由不同的文档定下。

完整的一览由管理号码的 IANA 保管(「Domain Name System (DNS) Parameters」)。种类有几十种,但平时会碰的大概十个左右。

🌙 这一点想记住:能在域名本身上写出类似 CNAME 效果的 ALIAS、ANAME,以及 Cloudflare 的 CNAME 展平——这些都不在 RFC 里。它们是服务方自己准备的功能,背后会转成 A 记录来回答。
方便是方便,但换了一家之后,未必还能这样写。规范定下的东西,和某家公司的功能。分开记住,往后就不会为难。

🌙最后

查着查着,最让我安静地吃惊的是:1987 年的一句话,正拦着今天的我的手。

「有 CNAME 的话,就不能有别的数据」。将近四十年前写下的一行,为的是让本名和别名的内容不会互相矛盾。就因为它,今天的我不能在域名本身上放别名。顺着困扰的形状追下去,是会好好地到达理由的——我这么想。

而且,不去查就不会知道的事,实在太多了。没有 A、MX 早就在工作、四个号码每次都换位置。读说明,和自己去查一次自己的域名,进到心里的深度是不一样的。

dig 这个工具,多半一开始就装着。若是好奇,就去查一次自己的域名吧。……那一行此刻在做什么,就看得见了🌙

🎬 这篇文章也做成了视频

📚出处

← 看看别的笔记