主题
换绑、退役、并行:域名变更的正确顺序
给一个服务换域名,看起来是"改一条 DNS 记录"的事。但在隧道/反向代理这套结构里,实际要动的是四层:
- DNS 记录(域名指向哪)
- 隧道的 ingress 规则(哪个域名转发到哪个本地端口)
- 应用侧的凭据绑定(有的隧道应用靠 appName 关联)
- 目标服务自己的 Host 白名单 / 站点 URL(不改会 400 或重定向到旧域名)
漏掉任何一层,症状都是"域名能解析、但打不开",而且每一层的报错都不一样。这篇是这套操作里我固定下来的顺序。
先搞清楚:你要做的是哪一种
- 换绑:服务不变,域名换一个(
old.example.com→new.example.com) - 退役:域名彻底不要了,服务留或删
- 并行:两个域名同时指向同一个服务(迁移期用,最安全)
并行最安全的理由很实际:新旧两个域名同时可用,你可以慢慢改客户端/书签,出问题随时回退。所以下面所有流程我都是在"并行"状态下做的。
顺序(我实际用的)
第 1 步:加新域名的 ingress 规则,不动旧的
在隧道配置里追加一条新规则,旧规则保持原样:
json
{
"ingress": [
{ "hostname": "new.example.com", "service": "http://localhost:3000" },
{ "hostname": "old.example.com", "service": "http://localhost:3000" },
{ "service": "http_status:404" }
]
}⚠️ 大多数隧道配置接口是整体覆盖语义,不是"增量追加"。所以你要先把现有配置读出来,追加一条,再整体写回去。
bash
# 先读
curl -s -H "Authorization: Bearer $CF_TOKEN" \
"https://api.cloudflare.com/client/v4/accounts/$ACC/cfd_tunnel/$TID/configurations" \
| jq '.result.config'读不出来就别写。 只看界面截图去手写一份 ingress,是最容易把别的服务搞挂的做法——我见过一次"改一条规则,结果三个域名同时 502"。
第 2 步:加 DNS 记录
新域名要有一条指向隧道的 CNAME:
new.example.com CNAME <tunnel-id>.cfargotunnel.com (proxied)如果隧道应用有"注册应用域名"这类接口,通常会顺带建这条记录。但要验证,不要假设。
第 3 步:等生效,然后用 DoH 和 --resolve 双重验证
刚建的记录,本机查经常是 NXDOMAIN —— 那是上游 DNS 的负缓存(它记住了"这个域名不存在"一段时间)。这不代表记录没建好。
bash
# 用公共 DoH 查真实结果
curl -s "https://doh.pub/dns-query?name=new.example.com&type=A" \
-H 'accept: application/dns-json'
# 或者跳过 DNS,直接指定 IP 测
curl --resolve new.example.com:443:203.0.113.10 https://new.example.com/ -o /dev/null -w '%{http_code}\n'两层都过了,才算"域名真的通了"。
第 4 步:改目标服务自己的配置
这一步最容易被忘。服务通常维护着自己的"我是谁":
- 站点 URL(WordPress 的
home/siteurl、笔记应用的APP_URL) - 允许的 Host 头 / CORS 白名单
- cookie 的 domain
不改的表现:页面能打开,但所有链接还指向旧域名;或者登录状态在跳转后失效;或者直接 400 Bad Request(Host 不匹配)。
第 5 步:旧域名留够时间,再退役
退役顺序反过来:先删 ingress → 再删 DNS → 最后删凭据。
原因是:先删 DNS 的话,如果 ingress 还在,会有人用旧域名访问到"能解析但连不上";反过来先删 ingress(旧域名命中兜底 404),至少错误是干净的。
⚠️ DNS 记录不一定能通过 API 删。我用的那套隧道应用就没有"删除 DNS 记录"的接口(试了几个常见端点全 404),残留的 CNAME 只能去 Cloudflare 控制台手删。
⚠️ 凭据/绑定关系里也会留残影。比如 app_domains.json 里可能还留着已删除 appName 的条目。这类残影一般无害(不参与路由),别顺手去清理,容易连带把现役的删掉。
三个反复出现的坑
1. 一个 appName 只能绑一个域名
有的隧道应用用"应用名"做凭据维度,一个 appName 只能对应一个域名。想加第二个域名必须新建凭据,而这类应用往往把凭据缓存在内存里 —— 新建完不重启不生效。
2. 免费二级域名不能 CNAME 到隧道
某些免费二级域名服务只允许 A 记录,不允许 CNAME。而隧道需要的是 cfargotunnel.com 的 CNAME。这种情况下只能在那边直接写 A 记录指向 Cloudflare 的 IP —— 这又绕开了 tunnel 的路由匹配,实际是"直连 CF 边缘再回落",能不能通取决于那条链路。
结论:免费域名适合做"绕开 CF 的备用入口",不适合做隧道域名。
3. 退役一个域名之后,别忘了还有谁在用
书签、客户端配置、OAuth 回调地址、Webhook 地址、别人的收藏。退役前在日志里查一下旧域名最近有没有访问:
bash
grep -c "old.example.com" /var/log/apps/<app>.log检查清单
换绑/并行:
- 读现有 ingress → 追加新规则 → 整体写回(别手写全量)
- 建 DNS(CNAME →
cfargotunnel.com,proxied) - DoH +
--resolve双验证 - 改服务侧的站点 URL / Host 白名单 / cookie domain
- 新旧域名并行跑一段时间
退役:
- 日志确认没有访问
- 删 ingress → 删 DNS(可能得手删)→ 删凭据
- 别去清理配置里的历史残影
一句话版本:域名变更真正的风险不在 DNS,在整体覆盖式的 ingress 写回。先读、追加、再写,永远不要在看不到现有配置的情况下改隧道规则。