查询 32 次,耗时 0.2169 秒

域名与服务器平滑迁移实战:从 DNS TTL、DNSSEC 到 HTTPS 回源的可验证切换方案

xiaobinz08

New member

xiaobinz08 Rep
0
0
0
Rep
0
xiaobinz08 Vouches
Vouches
0
1 MONTH
1 1 MONTH OF SERVICE
xiaobinz08 获得
0
0
0
获得
0
xiaobinz08 凭证
0
0
0
凭证
0
主题
3
点赞
0
HakB
1 月
在社区成长 1 月
LEVEL 1 1 XP
 
一、背景

更换云服务器、机房或 CDN 时,真正容易出问题的往往不是复制文件,而是 DNS 缓存、证书、源站配置和回滚路径。常见故障包括:域名已经解析到新服务器,但部分用户仍访问旧地址;HTTPS 证书在新节点上未正确部署;启用 DNSSEC 后直接修改权威 DNS,导致域名出现 SERVFAIL;数据库切换期间新旧站点同时接受写入,产生数据分叉。

本文给出一套适用于普通网站和 API 服务的平滑迁移流程。示例域名统一使用 example.com,地址使用文档保留网段 192.0.2.0/24 与 2001:db8::/32,不对应真实目标。所有验证命令都应针对自己有管理权限的域名和服务器执行。

本文的风险边界是:DNS 层面可以尽量降低不可达时间,但无法承诺全球递归解析器在某一秒同时完成更新;涉及数据库写入的业务,还必须由应用层提供只读窗口、单写节点或数据同步机制。

二、核心原理

1. TTL 与缓存

DNS 记录的 TTL 表示递归解析器通常可以缓存该结果的时间。例如 A 记录 TTL 为 3600 秒,修改后,部分解析器可能继续使用旧地址约一小时。降低 TTL 只对“降低之后重新获取到该记录的缓存”生效,因此不能在切换前一分钟才把 TTL 从 86400 改为 300。

2. 权威 DNS 与注册局委派

域名注册商处配置的 NS 记录决定注册局将查询委派给哪些权威 DNS。只修改 A、AAAA、CNAME 记录,通常不涉及委派变化;更换 DNS 服务商则需要修改 NS,风险更高,还可能涉及父区 DS 记录和 DNSSEC 信任链。

3. 正向代理与反向代理

Nginx、Caddy 等反向代理负责接收公网请求、终止 TLS,并转发到本机或内网应用。迁移时应先用本地 hosts 或 curl 的 --resolve 参数测试新服务器,而不是提前修改公共 DNS。

4. 可验证结论

迁移不能只以“浏览器能打开”为验收标准。至少应分别验证:权威 DNS 返回值、多个公共递归解析器返回值、TLS 证书链、HTTP 状态码、应用健康检查、静态文件、登录或下单等关键路径、旧服务器访问日志是否逐步下降。

三、前置条件

1. 拥有域名 DNS 管理权限、旧服务器和新服务器的管理权限。
2. 已记录当前 A、AAAA、CNAME、MX、TXT、CAA、NS 等配置,可从 DNS 控制台导出区文件更好。
3. 新服务器已安装操作系统安全更新、Web 服务、运行时及必要依赖。
4. 已确定数据迁移策略。纯静态站点可直接同步;动态站点应评估数据库、上传文件、队列任务和定时任务。
5. 已准备回滚方案,旧服务器至少保留到最大 TTL、业务观察期和日志确认全部通过之后。
6. 防火墙只开放必要端口。典型公网端口为 TCP 80、443;SSH 管理端口应限制来源地址或通过 VPN、堡垒机接入。

四、分步骤实践

步骤 1:盘点现有 DNS 和服务状态

先保存当前公开结果:

dig example.com A +noall +answer
dig example.com AAAA +noall +answer
dig www.example.com CNAME +noall +answer
dig example.com MX +noall +answer
dig example.com NS +noall +answer
dig example.com CAA +noall +answer

直接询问权威服务器可以减少递归缓存干扰。先通过 dig example.com NS 找到权威服务器,再执行:

dig @ns1.dns-provider.example example.com A +noall +answer

同时记录旧站点响应:

curl -I https://example.com/
curl -sS https://example.com/health

如果没有健康检查端点,建议添加一个只返回服务状态和版本号、但不泄露环境变量、数据库地址或密钥的端点。例如返回 {"status":"ok","release":"2025.03"} 即可。

步骤 2:提前降低 TTL

假设当前 TTL 是 86400 秒,计划两天后迁移,可以先将准备变更的 A、AAAA 或 CNAME 记录降至 300 秒。至少等待原 TTL 完整经过一次后,再执行正式切换。

不建议长期将所有记录都设为 60 秒。过低 TTL 会增加权威 DNS 查询量,也不能消除递归解析器异常缓存、客户端 DNS 缓存以及连接复用造成的延迟。300 至 600 秒通常是迁移窗口内较实用的范围,最终值应根据 DNS 服务能力和业务需求决定。

步骤 3:部署并加固新服务器

以 Debian/Ubuntu 为例,先更新软件包:

sudo apt update
sudo apt upgrade

创建独立部署用户,避免应用长期以 root 身份运行:

sudo adduser deploy
sudo usermod -aG sudo deploy

使用公钥登录后,再评估关闭 SSH 密码认证。修改前必须保留一个已验证可用的会话,避免把自己锁在服务器之外。可在 /etc/ssh/sshd_config.d/ 下新增配置:

PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes

检查配置并平滑重载:

sudo sshd -t
sudo systemctl reload ssh

防火墙规则示例:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 198.51.100.10 to any port 22 proto tcp
sudo ufw enable

其中 198.51.100.10 必须替换为自己的固定管理出口地址。若出口地址不固定,应优先使用 VPN 或云厂商的安全接入方案,不要照抄后导致失联。

步骤 4:配置 Nginx 与应用回源

一个最小化的反向代理示例如下:

server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;

location / {
proxy_pass http://127.0.0.1:8080
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
}
}

保存后检查并重载:

sudo nginx -t
sudo systemctl reload nginx

如果前面还有 CDN 或负载均衡器,不能无条件信任客户端提交的 X-Forwarded-For。应只信任已知代理出口网段,并按所用组件文档配置 real_ip_header 与 set_real_ip_from,否则访问控制和审计日志可能被伪造来源地址影响。

步骤 5:在不改公共 DNS 的情况下验证新节点

假设新服务器 IPv4 地址为 192.0.2.20,可使用 curl 强制将域名解析到新地址,同时保留正确的 Host 和 TLS SNI:

curl --resolve example.com:80:192.0.2.20 http://example.com/ -I
curl --resolve example.com:443:192.0.2.20 https://example.com/ -I
curl --resolve example.com:443:192.0.2.20 https://example.com/health

检查证书:

openssl s_client -connect 192.0.2.20:443 -servername example.com -showcerts </dev/null

这里应确认域名匹配、证书未过期、中间证书完整,并检查应用返回是否确实来自新版本。可以临时增加一个不包含敏感信息的响应头,例如 X-Release: 2025.03.08,用于区分新旧节点。

浏览器测试也可以临时修改本机 hosts,但测试后必须删除,避免误判公共 DNS 已经生效。相比之下,curl --resolve 只影响单次命令,边界更清晰。

步骤 6:迁移数据并控制写入

静态文件可使用 rsync:

rsync -aHAX --delete /srv/www/ [email protected]:/srv/www/

--delete 会删除目标端不存在于源端的文件,执行前应先使用 --dry-run 检查:

rsync -aHAX --delete --dry-run /srv/www/ [email protected]:/srv/www/

动态业务不能仅复制一次数据库后立即切 DNS。可选方案包括:短暂维护窗口内停止写入并完成最终增量同步;建立数据库复制后再提升新节点;让旧节点将写请求统一转发到新后端。无论采用哪种方式,都应明确“唯一写入源”,防止新旧节点各自产生无法自动合并的数据。

步骤 7:申请和验证 HTTPS 证书

可使用 ACME 客户端申请证书。若使用 HTTP-01 验证,公网 DNS 尚未切换时,验证请求可能仍到达旧服务器。可选择:先在旧节点完成验证并安全迁移证书;使用 DNS-01;或在切换后立即签发,但这会扩大故障窗口。

DNS-01 适合预先签发,也支持通配符证书,但 DNS API 凭据权限较高。应尽量限制为指定域名的 TXT 记录修改权限,并放在 root 可读的权限文件中,不得写入公开仓库或 Web 目录。

部署证书后重新执行 openssl s_client 和 curl --resolve,不能只看 Nginx 是否启动成功。

步骤 8:执行 DNS 切换

确认数据、应用、证书和防火墙全部通过后,将 A 记录从旧地址改为新地址,例如 192.0.2.20。如果新服务器没有稳定可用的 IPv6,不要保留指向错误位置的 AAAA 记录。部分客户端会优先尝试 IPv6,一个失效的 AAAA 记录可能表现为“有人能打开、有人超时”。

切换后分别检查权威 DNS 和公共递归解析器:

dig @ns1.dns-provider.example example.com A +short
dig @1.1.1.1 example.com A +short
dig @8.8.8.8 example.com A +short
dig @9.9.9.9 example.com A +short

还可以使用 trace 观察委派路径:

dig +trace example.com A

公共 DNS 返回一致不代表所有终端缓存都已更新,因此旧节点必须继续提供服务。观察新旧节点访问日志、错误率、响应时间和关键业务指标,而不是仅反复刷新首页。

步骤 9:DNSSEC 场景的特别处理

如果只是同一 DNS 服务商内修改 A 记录,通常由服务商正常重新签名即可,不应随意删除 DS。

如果要更换权威 DNS 服务商,必须先确认域名是否启用 DNSSEC:

dig example.com DS +dnssec
dig example.com DNSKEY +dnssec

存在 DS 记录意味着父区建立了信任链。直接把 NS 改到一套未承载匹配 DNSKEY 的新权威服务器,验证型递归解析器可能返回 SERVFAIL。

较稳妥的流程取决于新旧服务商是否支持 DNSSEC 密钥交接。常见保守方案是:提前降低相关 TTL;确认新服务商区记录完整;按双方文档完成 DNSKEY/DS 交接;从验证型解析器确认链路有效;再修改 NS。若无法完成安全交接,也可以在变更 NS 前按规范撤销旧 DS、等待缓存失效,再迁移并重新启用 DNSSEC,但这期间失去 DNSSEC 保护。具体等待时间必须依据父区 DS TTL、旧区记录 TTL 和服务商流程计算,不能套用固定的“等五分钟”。

可使用以下命令做本地验证:

delv example.com A
dig @1.1.1.1 example.com A +dnssec

判定标准不是响应里简单出现 ad 字符就万事大吉,还应核对新旧委派、DS、DNSKEY 和签名有效期。

步骤 10:观察、回滚与收尾

建议在切换期间重点观察:

1. HTTP 5xx 比例和网关超时。
2. 新旧服务器请求量变化。
3. 数据库连接数、复制延迟和慢查询。
4. TLS 握手错误与证书域名不匹配。
5. CDN 回源错误、缓存命中率和真实客户端地址记录。
6. 邮件相关域名是否受到误改影响,尤其是 MX、SPF、DKIM、DMARC。

若新节点出现严重问题,且数据模型允许回滚,可把 A/AAAA 恢复为旧地址。但如果新节点已经接受写入,直接回滚可能丢失新增数据。此时应先处理数据回流或将业务临时切为只读。DNS 回滚不等于数据回滚,这是迁移中最需要提前定义的边界。

确认旧服务器已基本无真实流量后,再恢复合理 TTL,例如 1800 或 3600 秒。旧节点不要在切换几分钟后立即销毁,建议至少覆盖原最大 TTL、客户端缓存偏差和业务观察周期。下线前删除 DNS 中不再使用的地址,撤销旧服务器凭据、备份并核验必要日志,再释放资源。

五、风险与注意事项

1. 不要只修改 www,而遗漏根域名,或反过来。
2. 同时存在 A 和 AAAA 时必须分别验证;错误的 IPv6 配置是典型的间歇性故障来源。
3. CNAME 不能与同名的其他常规记录随意共存,根域是否支持类似 ALIAS/ANAME 取决于 DNS 服务商实现。
4. 切换 DNS 不会自动迁移邮件。误改 MX、SPF、DKIM 或 DMARC 可能导致邮件退信或进入垃圾箱。
5. 不要在日志、命令历史和代码仓库中暴露 DNS API Token、私钥或数据库密码。
6. 启用 HSTS 前确认所有相关子域均支持 HTTPS。带 includeSubDomains 或 preload 的错误配置可能造成长期影响。
7. rsync 的 --delete、数据库覆盖导入、证书目录同步都属于破坏性操作,必须先备份并做 dry-run。
8. 若使用 CDN,DNS 查询看到的通常是 CDN 地址。源站验证应结合 CDN 控制台、回源日志和受限测试入口完成,不能据此错误判断 DNS 未生效。

六、常见问题

问:TTL 已设为 300,为什么十分钟后仍有人访问旧服务器?
答:可能是降低 TTL 前的旧缓存尚未到期,也可能存在操作系统、浏览器、运营商递归缓存或长连接复用。应从旧服务器日志确认来源和 Host,并保留旧节点服务能力,而不是立刻关机。

问:能否通过 ping 判断迁移成功?
答:不能。服务器可能禁用 ICMP,CDN 地址也不等于源站地址。应使用 dig 验证 DNS、openssl 验证 TLS、curl 验证 HTTP,并执行真实业务健康检查。

问:新服务器 curl IP 正常,但访问域名返回默认证书,原因是什么?
答:通常是 SNI 或虚拟主机未匹配。直接 curl https://ip 不能完整模拟域名访问,应使用 curl --resolve,并检查 Nginx 的 server_name、监听端口和证书绑定。

问:切换时一定要停机吗?
答:静态站点通常不需要。动态站点是否停机取决于数据一致性方案。没有数据库复制、共享存储或单写控制时,短暂只读窗口往往比冒险双写更可控。

问:修改 DNS 服务商后出现 SERVFAIL 应先查什么?
答:优先检查父区 NS 是否正确、权威服务器是否可达、区文件是否加载,以及域名是否残留不匹配的 DS。启用 DNSSEC 的域名不要通过反复随意修改记录碰运气,应核对完整信任链。

七、总结

一次可靠的域名与服务器迁移,应遵循“先部署、再旁路验证、控制数据写入、最后切 DNS”的顺序。DNS 只负责把名称指向服务入口,不能替代证书部署、应用健康检查和数据一致性设计。可操作的验收标准应包括:权威 DNS 返回新记录,多个递归解析器逐步更新,TLS 证书链正确,HTTP 与关键业务路径通过,新节点指标稳定,旧节点流量按 TTL 预期下降,并且回滚方案在数据层面仍然成立。

迁移中最危险的做法,是把浏览器一次访问成功当作全局成功,或把 DNS 恢复旧地址当作完整回滚。保留证据、逐项验证并明确风险边界,才能把不可避免的缓存差异控制在可观察、可恢复的范围内。
 

break

New member

break Rep
0
0
0
Rep
0
break Vouches
Vouches
0
1 MONTH
1 1 MONTH OF SERVICE
break 获得
0
0
0
获得
0
break 凭证
0
0
0
凭证
0
主题
6
点赞
0
HakB
1 月
在社区成长 1 月
LEVEL 20 100 XP
 
建议在正式切换前做一次“版本指纹”验证,避免新旧节点内容看似正常却实际混流。可让健康检查返回发布版本或构建号,并分别执行:curl --resolve example.com:443:192.0.2.20 https://example.com/health;切换后再从权威 DNS、公共递归 DNS 及旧 IP 访问该端点比对。动态站点还应在切换前停止旧节点的定时任务和消费队列,防止 DNS 已更新但旧节点继续写库或重复发任务。若启用 DNSSEC,更换权威 DNS 时应先确认新服务商生成的 DS 与 DNSKEY 匹配,再调整注册局 DS,避免信任链断裂。
 
顶部