hostname和domain

发布于

事情起因很简单。

我在 Fedora 44 上给这台笔记本起名字,想当然地写了:

sudo hostnamectl set-hostname wj.luchador.dev

然后跑了一遍 hostnamectl status,屏幕上跳出的结果让我愣住了:

Static hostname: wjluchador.dev
Pretty hostname: wj@luchador.dev

我设的是 wj.luchador.dev
系统却把它改成了 wjluchador.dev,Pretty 名还变成了 wj@luchador.dev

两个点没了,只剩一个。
点号被吃掉了,名字还被拼在了一起。

于是第一个疑问自然冒出来:

为什么在 Fedora 上把 hostname 设成二级域名,它会自动变成一级域名?

第一反应:一定是谁在背后改我的名字

作为日常和网络打交道的人,我第一时间怀疑的不是自己,而是系统里那些“好心”的服务。

会不会是 NetworkManager 连上 Wi-Fi 后,把 DHCP 推过来的主机名盖上去了?
会不会是 systemd-hostnamed 把 FQDN 强行剥成了短名?
会不会是路由器上的反向 DNS(PTR)又把名字抢回去了?

这些怀疑都合理。Fedora 上确实经常出现 hostname 被覆盖的情况:DHCP、NetworkManager、反向解析,都可能动到 Transient hostname。

可问题是,我明明是用 hostnamectl 设的 Static hostname。
它不是临时名,按理说不该这么轻易被改掉。

所以第二个疑问来了:

我就是通过 hostnamectl 设置的,为什么结果还是不对?

真正让我卡住的,不是覆盖,而是“清洗”

继续追问之后,事情开始变得更怪。

我不是单纯地“设不进去”,而是系统看起来像在“理解”我的输入,然后自作主张地改写它:

这不像简单的覆盖,更像某种字符串清洗。

于是第三个疑问出现了,也是整件事里最核心的那个:

我为什么不能把 hostname 设成带两个点的名字?

从 Web 开发者的直觉看,这几乎不可理解。

浏览器里的 hostname,本来就是 wj.luchador.dev 这种东西。
Nginx 的 server_name 也是它。
证书绑定的也是它。
HTTP 请求头里的 Host 还是它。

我每天都在和带点的名字打交道。
为什么到了 Linux 系统里,它突然就不认了?

原来我把两个完全不同的“hostname”叠在了一起

后来我才意识到,困惑的根源不在 Fedora,而在我自己的职业惯性。

作为 Web 开发者,我嘴里说的 hostname,几乎永远指的是应用层概念:

这些场景里,hostname 就应该是全限定域名(FQDN)。

但 Linux 系统里的 hostname,说的是另一件事。

它更接近机器在本机和局域网里的“小名”:

也就是说:

我一直把这两个词当成同一个东西,所以才会觉得:

Linux 内部设置 hostname,当然也应该写成全限定域名。

这个假设一旦成立,后面所有怪现象都会显得像系统在捣乱。
可如果这个假设本身就是错的,那系统的行为反而开始说得通了。

系统到底做了什么

当我执行:

sudo hostnamectl set-hostname wj.luchador.dev

而没有加 --static 时,hostnamectl 会同时尝试处理多种主机名:

于是系统大概经历了这样一场“内心戏”:

  1. 收到 wj.luchador.dev
  2. 发现它不像一个干净的短主机名
  3. 先把它当成 Pretty 名处理,结果变成了 wj@luchador.dev
  4. 再从 Pretty 推导 Static 时,把点号当成特殊符号清洗掉
  5. 最终拼出了一个它觉得更“合规”的 wjluchador.dev

所以这不是 RFC 规定“主机名只能有一个点”。
更像是:我把一个 FQDN 塞进了本该放短名的格子里,systemd 用自己的清洗逻辑帮我“纠正”了一次。

纠正的结果很丑,但动机并不神秘。

那网络标准到底怎么说

顺着这个点继续想,第四个疑问就来了:

为什么 Static hostname 会变成只有一个点?我对网络标准其实并不熟。

如果抛开工具细节,回到更老的网络习惯,事情其实很朴素:

点号在这里不是装饰,而是层级分隔。

.dev 像大院子,
luchador.dev 像院子里的一栋楼,
wj.luchador.dev 才是楼里的某个房间。

Linux 内核初始化时,真正需要记住的,往往只是房间号:wj
FQDN 则更适合交给 DNS、/etc/hosts、证书、邮件服务这些“对外身份系统”去处理。

所以正常做法其实是:

sudo hostnamectl set-hostname wj

然后在 /etc/hosts 里把小名和学名绑在一起:

127.0.0.1   localhost localhost.localdomain wj.luchador.dev wj
::1         localhost localhost.localdomain wj.luchador.dev wj

这样:

机器既有干净的内部名字,也有完整的外部身份。

那什么时候用小名,什么时候用学名

一旦接受了“hostname 不等于 FQDN”,下一个问题就很自然:

什么情况下该用 wj,什么情况下该用 wj.luchador.dev

我给自己整理成一句很实用的话:

对内用小名,对外用学名。

适合用 wj 的时候:

适合用 wj.luchador.dev 的时候:

换句话说,短名负责“这台机器是谁”,
FQDN 负责“外面的世界怎么找到这台机器对应的服务”。

可是网关怎么知道我是谁

到这里,最后一个真正关键的疑问才浮出来:

既然本机 hostname 只该设成小名,那我藏在网关后面时,外面的人输入 wj.luchador.dev,网关又怎么锁定到我这台主机?

这个问题之所以会问出来,恰恰说明前面的误解还没完全拆开。

因为如果我默认“域名等于机器内部名字”,那就会以为:

外面要找到我,必须先知道我本机叫什么。

但真实链路根本不是这样。

假设:

流程其实是:

  1. 浏览器问 DNS:wj.luchador.dev 是谁?
  2. DNS 回答:去找 11.22.33.44
  3. 请求到达网关
  4. 网关靠端口映射,或者靠反向代理看 Host: wj.luchador.dev,再转发到 192.168.1.50

注意,整条链路里,没有一步需要读取我本机的 Linux hostname。

网关认的是:

而不是 /etc/hostname 里写的那个小名。

所以本机叫 wj,完全不影响外面通过 wj.luchador.dev 找到我。
真正把“学名”接到“这台机器上某个服务”的,是 DNS、端口转发、反向代理,以及本机 Web 服务自己的虚拟主机配置。

/etc/hosts 里的 wj.luchador.dev,更多是给本机自己用的:

它不是公网寻址的主路径。

这场误会为什么会发生在我身上

回头看,整件事最有意思的地方,不是 Fedora 改了我的名字,而是它暴露了我长期没拆开的一层概念混淆。

我是 Web 开发者。
我每天都在 HTTP、浏览器、证书、反向代理里使用 hostname 这个词。
在那个世界里,hostname 几乎天然等于 FQDN。

所以当我第一次给 Linux 机器起名时,我会本能地写出:

wj.luchador.dev

不是因为我读过某份文档要求这么做,
而是因为这个名字在我的日常工作语境里,看起来“才像一个真正的主机名”。

于是疑问一层层长出来:

  1. 为什么设成二级域名会被改成一级?
  2. 为什么 hostnamectl 也会改坏?
  3. 为什么不能保留两个点?
  4. 这是不是 RFC 规定?
  5. 那是不是应该只设成 wj
  6. 小名和学名分别用在什么地方?
  7. 网关后面又如何靠 FQDN 找到我?

这些问题表面上看是在排障,
底层其实都在回答同一件事:

Linux 的 hostname,和浏览器里的 hostname,不是同一个抽象。

最后我怎么设

对我这台日常开发用的 Fedora 来说,标准做法已经很清楚了:

sudo hostnamectl set-hostname wj

再在 /etc/hosts 里补上:

127.0.0.1   localhost localhost.localdomain wj.luchador.dev wj
::1         localhost localhost.localdomain wj.luchador.dev wj

如果哪天某个软件死活要求 Static hostname 必须是 FQDN,再考虑:

sudo hostnamectl set-hostname wj.luchador.dev --static

但那是例外,不是默认。

默认情况下,机器内部保留小名,对外身份交给 DNS 和 /etc/hosts

写在最后

这次排查没有换来什么高深技巧,只换来一个很便宜、却很值钱的区分:

以前我总觉得系统“自作聪明”。
现在回头看,更像是我把应用层的习惯,直接套进了系统层。

名字被改掉的那一刻很烦。
但正因为烦,才把这两个长期叠在一起的概念,终于拆开了。

参考讨论:Google AI Mode 对话