从只懂 A 记录,到重新理解 DNS:普通解析、泛域名和证书验证

最近在折腾 frp、Caddy、内网穿透和域名分流的时候,我突然发现一个问题:

我以前对 DNS 的理解其实挺片面的。

以前我理解 DNS,大概就是:

域名 -> IP

比如:

weini.xin -> 服务器 IP
www.weini.xin -> 服务器 IP

也就是说,我过去主要只知道 A 记录

A 记录确实是 DNS 里最常见、最直观的一种记录,但这次深入折腾之后,我发现 DNS 远不只是“域名转 IP”这么简单。

它其实同时参与了:

域名寻址
服务入口命名
泛域名管理
证书验证
权属证明
公网入口治理

这次算是对 DNS 的理解上了一层楼。


一、我以前理解的 DNS:域名指向 IP

最普通的 DNS 使用方式,就是添加一条 A 记录。

比如:

abc.weini.xin A 123.123.123.123

意思是:

访问 abc.weini.xin 的时候,去 123.123.123.123 这台服务器

这就是最常见的 DNS 解析。

如果我在浏览器访问:

http://abc.weini.xin

大概流程是:

浏览器要访问 abc.weini.xin
        ↓
查询 DNS
        ↓
DNS 返回 123.123.123.123
        ↓
浏览器连接这台服务器

这个过程很好理解。

所以我以前一直觉得:

DNS 不就是把域名解析成 IP 吗?

这个理解没错,但只是 DNS 的第一层。


二、普通 DNS 解析:一个名字对应一个目标

普通解析通常是这种形式:

abc.weini.xin -> 服务器 IP
api.weini.xin -> 服务器 IP
www.weini.xin -> 服务器 IP

也就是你每需要一个明确的域名,就添加一条记录。

比如:

abc.weini.xin A 123.123.123.123
api.weini.xin A 123.123.123.123
www.weini.xin A 123.123.123.123

这很好理解,也很适合正式服务。

比如:

weini.xin       主站
www.weini.xin   主站
api.weini.xin   正式 API
blog.weini.xin  博客

这些域名比较稳定,单独配置 A 记录完全没问题。

但是如果我有很多开发服务、测试服务、临时服务,就会变麻烦。

比如:

mcp.dev.weini.xin
api.dev.weini.xin
demo.dev.weini.xin
ghost-test.dev.weini.xin
test-api.dev.weini.xin

如果每一个都手动添加 DNS 记录,会很烦。

这时候就引出了泛域名解析。


三、泛域名解析:一次配置,覆盖一批子域名

泛域名解析就是:

*.dev.weini.xin A 123.123.123.123

它的意思是:

所有 xxx.dev.weini.xin 都解析到 123.123.123.123

比如:

mcp.dev.weini.xin
api.dev.weini.xin
demo.dev.weini.xin
abc.dev.weini.xin
anything.dev.weini.xin

这些都会自动解析到同一台服务器。

这个体验非常爽。

以前新增一个服务,我要想:

我要不要去 DNS 控制台加一条记录?
我要不要配置新域名?
我要不要记住这个端口?

有了泛域名之后,我只要提前配置:

*.dev.weini.xin A 服务器 IP
*.test.weini.xin A 服务器 IP

后面所有开发和测试服务都可以直接挂进去。

比如:

mcp.dev.weini.xin
api.dev.weini.xin
demo.test.weini.xin
client-a.test.weini.xin

DNS 层不用再改。

这个时候我第一次明显感觉到:

DNS 不只是域名解析,它还能帮我规划服务入口的命名空间。


四、普通解析和泛域名解析的区别

普通解析更像是:

我明确指定某一个名字去哪

比如:

api.weini.xin -> 123.123.123.123

泛域名解析更像是:

我指定一整片名字都去哪

比如:

*.dev.weini.xin -> 123.123.123.123

对比一下:

普通解析:
api.weini.xin
www.weini.xin
blog.weini.xin
每个名字单独配置

泛域名解析:
*.dev.weini.xin
*.test.weini.xin
一整片子域名统一配置

所以我现在更倾向于这样规划:

weini.xin              正式主站
www.weini.xin          正式入口
api.weini.xin          正式 API,单独配置

*.dev.weini.xin        开发服务,泛域名
*.test.weini.xin       测试服务,泛域名

这样既不会污染主域名空间,又能让开发测试环境足够灵活。

这个分层我觉得很重要:

一级子域名留给正式服务
二级命名空间留给开发测试

也就是说,不一定要直接搞:

*.weini.xin

因为这会让所有一级子域名都进入泛解析范围,比如:

mail.weini.xin
admin.weini.xin
cdn.weini.xin
random.weini.xin

这有点太大了。

更稳的是:

*.dev.weini.xin
*.test.weini.xin

这样边界更清晰。


五、DNS 只负责“找到服务器”,不负责“服务分流”

这是这次很重要的一个认知。

比如我配置了:

*.dev.weini.xin A 123.123.123.123

那么:

mcp.dev.weini.xin
api.dev.weini.xin
demo.dev.weini.xin

都会到同一台服务器。

但是 DNS 只负责把它们都带到服务器。

它不负责判断:

mcp.dev.weini.xin 应该去 8120
api.dev.weini.xin 应该去 8122
demo.dev.weini.xin 应该去 8080

这个分流不是 DNS 做的。

真正分流的是服务器上的 Caddy、Nginx,或者 frp 的 HTTP Host 分流。

比如 Caddy 可以根据 Host 头判断:

Host: mcp.dev.weini.xin -> 转发到服务 A
Host: api.dev.weini.xin -> 转发到服务 B
Host: demo.dev.weini.xin -> 转发到服务 C

所以这句话很关键:

DNS 负责让请求找到服务器,Caddy/frp 负责让请求找到具体服务。

这也是我之前容易混的地方。


六、A 记录和 TXT 记录:一个负责 IP,一个负责字符串

这次还有一个很大的收获,就是理解了 TXT 记录。

以前我只熟悉 A 记录:

abc.weini.xin A 123.123.123.123

A 记录返回的是 IP。

但 TXT 记录返回的是一段字符串。

比如:

_acme-challenge.dev.weini.xin TXT "abcdefg"

它不是告诉浏览器访问哪台服务器。

它只是说:

_acme-challenge.dev.weini.xin 这个 DNS 名字下面,有一段文本 abcdefg

也就是说:

A 记录:某个名字 -> IP 地址
TXT 记录:某个名字 -> 一段字符串

这让我突然意识到,DNS 不只是能返回 IP。

它还能公开地返回各种信息。

比如 TXT 记录经常用于:

证书验证
域名所有权验证
邮箱 SPF
DKIM
DMARC
各种平台的域名认证

这一下我对 DNS 的理解就打开了。


七、普通 HTTPS 证书是怎么验证的?

以前我只知道 Caddy 可以自动申请 HTTPS 证书。

但我没认真想过:

证书机构凭什么相信这个域名是我的?

普通证书的验证方式大概是这样。

比如我要申请:

abc.weini.xin

的证书。

前提是 DNS 里有:

abc.weini.xin A 123.123.123.123

然后 Caddy 向证书机构申请证书。

证书机构会给 Caddy 一个随机字符串,比如:

xyz987

然后要求 Caddy 在这个地址返回它:

http://abc.weini.xin/.well-known/acme-challenge/某个路径

接着证书机构自己访问这个 URL。

访问过程是:

证书机构访问 abc.weini.xin
        ↓
DNS 把 abc.weini.xin 解析到服务器 IP
        ↓
请求到达 Caddy
        ↓
Caddy 返回刚刚那个随机字符串
        ↓
证书机构确认字符串正确
        ↓
签发证书

所以普通证书的关键不是:

证书机构看 A 记录里的 IP 是不是对的

而是:

证书机构通过 DNS 找到你的服务器,然后看你的服务器能不能返回正确验证码

换句话说:

普通证书验证的是:你能控制这个具体域名当前指向的 Web 服务。

DNS 在这里负责带路。

Caddy 在 HTTP 响应里交验证码。

证书机构负责检查验证码对不对。


八、通配证书是怎么验证的?

通配证书就不一样了。

比如我要申请:

*.dev.weini.xin

这张证书可以覆盖:

mcp.dev.weini.xin
api.dev.weini.xin
demo.dev.weini.xin
anything.dev.weini.xin

但是问题来了:

证书机构没法访问:

http://*.dev.weini.xin/.well-known/acme-challenge/xxx

因为 * 不是一个具体的域名。

它代表无限多个可能的子域名。

所以通配证书不能用普通 HTTP 路径验证。

它需要 DNS 验证。

流程大概是:

Caddy 申请 *.dev.weini.xin 通配证书
        ↓
证书机构生成一个随机字符串,比如 abcdefg
        ↓
证书机构要求添加:
_acme-challenge.dev.weini.xin TXT "abcdefg"
        ↓
Caddy 或者人手动去 DNS 里添加这条 TXT
        ↓
证书机构查询 DNS
        ↓
发现 TXT 里的字符串和自己给的一样
        ↓
证明你能控制 dev.weini.xin 这片 DNS
        ↓
签发 *.dev.weini.xin 通配证书

所以通配证书验证的是:

你能控制这个域名的 DNS。

不是验证某一台服务器。

这点很关键。


九、为什么 TXT 记录不能自己永久写死?

一开始我有个疑问:

既然通配证书需要:

_acme-challenge.dev.weini.xin TXT "某个字符串"

那我自己在阿里云 DNS 里写一个固定字符串,不就完了吗?

后来才理解,这个不行。

因为这个字符串不是我自己定的。

它是证书机构每次临时生成的随机验证码。

这就像短信验证码。

网站让你输入:

839201

你不能说:

我自己设一个 123456,以后你都认这个不就行了吗?

不行。

因为验证码必须是对方临时出的。

证书验证也是一样。

这次申请时,证书机构可能要求:

_acme-challenge.dev.weini.xin TXT "abc123"

下次续期时,可能变成:

_acme-challenge.dev.weini.xin TXT "xyz789"

它不是永久固定值。

所以手动添加 TXT 可以完成一次申请,但以后续期时还得再改。

这就是为什么通配证书要想自动续期,Caddy 需要 DNS 服务商的 API 权限。


十、阿里云 API Key 不是为了 DDNS,而是为了自动改 TXT 验证

这里也容易误会。

一开始听到 Caddy 需要阿里云 API Key,我下意识以为:

这不是变成 DDNS 了吗?我不是已经有 *.dev.weini.xin 泛解析了吗?

后来才明白不是一回事。

我已经配置好的:

*.dev.weini.xin A 服务器 IP

负责的是流量入口。

它可以长期固定。

而 Caddy 需要 DNS API,是为了在申请或续期通配证书时,自动创建或更新:

_acme-challenge.dev.weini.xin TXT "本次随机值"

也就是说,API Key 不是为了新增:

mcp.dev.weini.xin
api.dev.weini.xin
demo.dev.weini.xin

这些业务域名已经由泛解析覆盖了。

API Key 只是为了自动完成证书机构要求的 TXT 验证。

可以这么理解:

*.dev.weini.xin A 记录:
长期固定,负责所有 dev 子域名流量进入服务器

_acme-challenge.dev.weini.xin TXT 记录:
临时变化,负责通配证书申请和续期验证

这是两件完全不同的事。


十一、普通证书和通配证书的核心区别

现在我终于能把这两个东西分清楚了。

普通证书:

申请对象:abc.weini.xin
验证方式:HTTP 验证
验证内容:服务器能不能返回正确验证码
证明的是:你能控制这个具体域名对应的 Web 服务

通配证书:

申请对象:*.dev.weini.xin
验证方式:DNS TXT 验证
验证内容:DNS 里能不能写入正确验证码
证明的是:你能控制这个域名的 DNS

一句话总结:

普通证书:
DNS 负责带路,Caddy 在 HTTP 里交验证码。

通配证书:
不访问具体服务器,直接用 DNS TXT 交验证码。

这下就清楚了。


十二、结合 frp 和 Caddy 后,DNS 的价值一下子变大了

这次之所以对 DNS 有新理解,是因为它和 frp、Caddy 结合起来之后,价值变得很明显。

我的目标是:

内网服务很多
每个服务有自己的端口
我想通过公网域名访问它们
但不想每次都开端口、改 DNS、登录服务器

最开始的方式是:

公网服务器:18120 -> 内网服务:8120
公网服务器:18122 -> 内网服务:8122

这能用,但端口多了很乱。

后来改成:

mcp.dev.weini.xin -> Caddy -> frp -> 内网服务
api.dev.weini.xin -> Caddy -> frp -> 内网服务

再加上泛域名:

*.dev.weini.xin -> 公网服务器
*.test.weini.xin -> 公网服务器

DNS 这一层就变成了服务入口命名空间。

之后如果再配合 Caddy 通配入口和 frp HTTP Host 分流,就可以做到:

DNS 不用改
Caddy 不用改
安全组不用开新端口
新增服务只改 frpc

这个体验就非常优雅。


十三、我现在对 DNS 的新理解

以前我理解 DNS 是:

DNS = 域名转 IP

现在我觉得更准确的是:

DNS = 互联网服务的命名、寻址、验证和治理系统

A 记录解决:

这个名字应该去哪个 IP?

泛域名解决:

这一整片名字都应该去哪里?

TXT 记录解决:

这个名字下面公开声明了什么字符串?

证书验证利用 TXT 记录解决:

你是否真的控制这个域名?

Caddy 和 frp 利用 Host 解决:

这个请求到了服务器后,应该交给哪个服务?

所以整个链路变成:

DNS:负责名字和入口
证书机构:负责信任验证
Caddy:负责 HTTPS 和网关入口
frp:负责把请求带回内网服务
业务服务:只负责自己的功能

这比单纯“域名指向 IP”的理解要完整很多。


十四、这次最大的收获

这次最大的收获不是学会了怎么添加一条 TXT 记录,也不是学会了泛域名怎么配。

而是理解了:

DNS 不只是访问入口,也是信任体系的一部分。

普通访问时,DNS 负责告诉用户去哪里。

申请证书时,DNS 还可以用来证明你是不是有资格拥有这个域名。

尤其是通配证书:

*.dev.weini.xin

它不是靠访问某一台服务器来验证,而是靠 DNS TXT 来证明你控制整个命名空间。

这个认知对我很重要。

以前我只知道 A 记录。

现在至少我知道了:

A 记录:负责寻址
泛域名:负责批量命名空间
TXT 记录:负责字符串信息和验证
普通证书:HTTP 验证
通配证书:DNS TXT 验证

这次算是真正从“会配 DNS”往“理解 DNS”走了一步。

Read more

三台机器部署 ClickHouse 高可用集群实战记录

本文是一份可发布版部署记录。真实 IP、域名、账号、密码、下载链接、业务目录名、机器唯一标识等敏感信息已经替换为占位符。命令中的 <...> 需要按自己的环境替换。 目标与拓扑 这次目标是用三台数据节点部署一套 ClickHouse 高可用集群,拓扑采用: 1 shard x 3 replicas 含义是:集群只有一个逻辑分片,三台机器都保存同一份数据的完整副本。任意一台数据节点宕机时,只要 ClickHouse Keeper 仍然有多数派,剩余节点仍可继续提供读写服务。 规划节点如下: 主机名示例地址角色ch-01<ch-01-ip>ClickHouse Server + ClickHouse Keeperch-02<ch-02-ip>ClickHouse Server + ClickHouse Keeperch-03<ch-03-ip&

By ladydd

折腾记(二):接入火山引擎实时语音 API,家庭语音助手体验直接拉满

接上篇 上一篇用全开源组件(Whisper + Hermes + Edge-TTS)搭了个语音助手,能跑,但体验就是"能用"二字: * 中文识别只有 70 分,方言基本歇菜 * 英文唤醒词"Alexa"喊着别扭 * 说完到回复要等 4-8 秒 * 它说话的时候你插不了嘴 这些问题靠堆开源组件很难根治。于是我去试了火山引擎(字节跳动)的语音服务,结果直接换了条路。 这篇分两段:先讲怎么用火山引擎的 ASR/TTS 替换掉开源组件(小改),再讲怎么上端到端实时语音模型(大改)。 第一段:先把 ASR 和 TTS 换成火山引擎 为什么换 我用豆包输入法的时候发现它语音识别准得离谱。一查,豆包用的就是字节自家的火山引擎 Seed-ASR。开通后有免费额度(

By ladydd

折腾记(一):用全开源组件给家里搭一个语音助手,对接自己的 Hermes Agent

起因 事情是从一块 ESP32-S3 开发板开始的。 我手上有一块 Seeed Studio XIAO ESP32-S3 Sense,带摄像头和麦克风。最初的想法很美好:用这块板子做一个无线语音终端,对着它说话,连到我服务器上跑的 Hermes Agent(一个自托管的 AI agent),让它回答我。 但折腾到一半我突然意识到一件事:我的麦克风、音响、服务器全在家里,为什么要绕一圈用 ESP32?直接把麦克风和音响插到服务器上不就行了? ESP32 那条路(做无线拾音终端)当然也有价值,但那是"为了学嵌入式而学",不是解决问题的最短路径。于是这个项目就从"嵌入式项目"变成了"在服务器上拼一个语音助手"。这篇就记录后者。 教训零:先想清楚你要解决的是什么问题。很多时候最优解比你最初设想的简单得多。 目标

By ladydd

Kiro 的三种代理设置方法:本地、服务端、Remote

作为kiro的骨灰级用户,这篇是我自己折腾 Kiro / Kiro Remote / Ubuntu Server 代理问题后的复盘。 核心不是“怎么配一个代理”,而是先判断:到底是谁在访问外网? 谁访问外网,代理就要配给谁。 0. 先说结论 Kiro 相关代理大概分三类: 场景真正访问外网的进程在哪里代理应该配在哪里本地 KiroWindows / Mac 本机本机 Clash / Proxifier / 系统代理服务端 Kiro / CLIUbuntu Server 上的 shell、CLI、node、kiro 进程Ubuntu 的环境变量,比如 HTTP_PROXY / HTTPS_PROXYKiro Remote远程 Ubuntu 上的 ~/.kiro-server 和 extensionHost远程 Ubuntu 的 Kiro Server

By ladydd
陕公网安备61011302002223号 | 陕ICP备2025083092号