事情起因很简单。
我在 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 设置的,为什么结果还是不对?
真正让我卡住的,不是覆盖,而是“清洗”
继续追问之后,事情开始变得更怪。
我不是单纯地“设不进去”,而是系统看起来像在“理解”我的输入,然后自作主张地改写它:
- Pretty hostname 变成了
wj@luchador.dev - Static hostname 变成了
wjluchador.dev
这不像简单的覆盖,更像某种字符串清洗。
于是第三个疑问出现了,也是整件事里最核心的那个:
我为什么不能把 hostname 设成带两个点的名字?
从 Web 开发者的直觉看,这几乎不可理解。
浏览器里的 hostname,本来就是 wj.luchador.dev 这种东西。
Nginx 的 server_name 也是它。
证书绑定的也是它。
HTTP 请求头里的 Host 还是它。
我每天都在和带点的名字打交道。
为什么到了 Linux 系统里,它突然就不认了?
原来我把两个完全不同的“hostname”叠在了一起
后来我才意识到,困惑的根源不在 Fedora,而在我自己的职业惯性。
作为 Web 开发者,我嘴里说的 hostname,几乎永远指的是应用层概念:
- 浏览器地址栏里的域名
- HTTP 的 Host 头
- Nginx / Caddy 的虚拟主机名
- SSL 证书上的 Common Name / SAN
这些场景里,hostname 就应该是全限定域名(FQDN)。
但 Linux 系统里的 hostname,说的是另一件事。
它更接近机器在本机和局域网里的“小名”:
- 内核认识的节点名
- 终端提示符里的
@wj - 日志、审计、本机服务用来识别自己的代号
也就是说:
- 浏览器里的 hostname,是对外的学名
- Linux 里的 hostname,是对内的乳名
我一直把这两个词当成同一个东西,所以才会觉得:
Linux 内部设置 hostname,当然也应该写成全限定域名。
这个假设一旦成立,后面所有怪现象都会显得像系统在捣乱。
可如果这个假设本身就是错的,那系统的行为反而开始说得通了。
系统到底做了什么
当我执行:
sudo hostnamectl set-hostname wj.luchador.dev
而没有加 --static 时,hostnamectl 会同时尝试处理多种主机名:
- Pretty hostname:给人看的,格式很宽松
- Static hostname:写入
/etc/hostname,更严格 - Transient hostname:运行时、网络侧可能改动的临时名
于是系统大概经历了这样一场“内心戏”:
- 收到
wj.luchador.dev - 发现它不像一个干净的短主机名
- 先把它当成 Pretty 名处理,结果变成了
wj@luchador.dev - 再从 Pretty 推导 Static 时,把点号当成特殊符号清洗掉
- 最终拼出了一个它觉得更“合规”的
wjluchador.dev
所以这不是 RFC 规定“主机名只能有一个点”。
更像是:我把一个 FQDN 塞进了本该放短名的格子里,systemd 用自己的清洗逻辑帮我“纠正”了一次。
纠正的结果很丑,但动机并不神秘。
那网络标准到底怎么说
顺着这个点继续想,第四个疑问就来了:
为什么 Static hostname 会变成只有一个点?我对网络标准其实并不熟。
如果抛开工具细节,回到更老的网络习惯,事情其实很朴素:
- Hostname 是名字,比如
wj - Domain 是所属组织,比如
luchador.dev - 两者拼起来,才是 FQDN:
wj.luchador.dev
点号在这里不是装饰,而是层级分隔。
.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返回wjhostname -f返回wj.luchador.dev
机器既有干净的内部名字,也有完整的外部身份。
那什么时候用小名,什么时候用学名
一旦接受了“hostname 不等于 FQDN”,下一个问题就很自然:
什么情况下该用
wj,什么情况下该用wj.luchador.dev?
我给自己整理成一句很实用的话:
对内用小名,对外用学名。
适合用 wj 的时候:
- 终端提示符
- 本机脚本
- 局域网共享
- 大多数只在本机跑的服务配置
适合用 wj.luchador.dev 的时候:
- 申请 SSL 证书
- 公网 DNS 解析
- 邮件服务器对外握手
- 跨机器、跨机房的服务发现
换句话说,短名负责“这台机器是谁”,
FQDN 负责“外面的世界怎么找到这台机器对应的服务”。
可是网关怎么知道我是谁
到这里,最后一个真正关键的疑问才浮出来:
既然本机 hostname 只该设成小名,那我藏在网关后面时,外面的人输入
wj.luchador.dev,网关又怎么锁定到我这台主机?
这个问题之所以会问出来,恰恰说明前面的误解还没完全拆开。
因为如果我默认“域名等于机器内部名字”,那就会以为:
外面要找到我,必须先知道我本机叫什么。
但真实链路根本不是这样。
假设:
- 公网用户访问
wj.luchador.dev - 网关公网 IP 是
11.22.33.44 - 我的 Fedora 在内网是
192.168.1.50
流程其实是:
- 浏览器问 DNS:
wj.luchador.dev是谁? - DNS 回答:去找
11.22.33.44 - 请求到达网关
- 网关靠端口映射,或者靠反向代理看
Host: wj.luchador.dev,再转发到192.168.1.50
注意,整条链路里,没有一步需要读取我本机的 Linux hostname。
网关认的是:
- DNS 记录
- 公网 IP
- 内网 IP
- 端口
- HTTP Host 头
而不是 /etc/hostname 里写的那个小名。
所以本机叫 wj,完全不影响外面通过 wj.luchador.dev 找到我。
真正把“学名”接到“这台机器上某个服务”的,是 DNS、端口转发、反向代理,以及本机 Web 服务自己的虚拟主机配置。
/etc/hosts 里的 wj.luchador.dev,更多是给本机自己用的:
- 本地开发时直接回环解析
- 本机服务自检时对得上名字
- 某些程序询问 FQDN 时有地方可查
它不是公网寻址的主路径。
这场误会为什么会发生在我身上
回头看,整件事最有意思的地方,不是 Fedora 改了我的名字,而是它暴露了我长期没拆开的一层概念混淆。
我是 Web 开发者。
我每天都在 HTTP、浏览器、证书、反向代理里使用 hostname 这个词。
在那个世界里,hostname 几乎天然等于 FQDN。
所以当我第一次给 Linux 机器起名时,我会本能地写出:
wj.luchador.dev
不是因为我读过某份文档要求这么做,
而是因为这个名字在我的日常工作语境里,看起来“才像一个真正的主机名”。
于是疑问一层层长出来:
- 为什么设成二级域名会被改成一级?
- 为什么
hostnamectl也会改坏? - 为什么不能保留两个点?
- 这是不是 RFC 规定?
- 那是不是应该只设成
wj? - 小名和学名分别用在什么地方?
- 网关后面又如何靠 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。
写在最后
这次排查没有换来什么高深技巧,只换来一个很便宜、却很值钱的区分:
wj是机器在系统里的名字wj.luchador.dev是机器在网络世界里的身份- 浏览器里的 hostname,属于 HTTP
- Linux 里的 hostname,属于操作系统
以前我总觉得系统“自作聪明”。
现在回头看,更像是我把应用层的习惯,直接套进了系统层。
名字被改掉的那一刻很烦。
但正因为烦,才把这两个长期叠在一起的概念,终于拆开了。
参考讨论:Google AI Mode 对话