域名 / DNS
本文范围
这篇文章只讲网站和接口上线时必须用到的域名 / DNS 运维链路:记录类型、解析链路、TTL、hosts 临时验证、云解析、内网 DNS、备案边界、Nginx server_name、证书域名验证、CDN 分段排障、解析切换和回滚。
本文不展开 DNS 协议全量细节、权威 DNS 软件搭建、DNSSEC 全套治理、智能解析产品选型和 CDN 深度调优。后面出现 Nginx、HTTPS、CDN,只围绕“域名访问是否能稳定到达正确入口”来讲。
读完以后你应该能判断:域名到底解析到哪里、缓存为什么没生效、Nginx 为什么匹配错站点、证书为什么不覆盖域名,以及生产切换时怎么把 DNS 当成一次发布来做。
前置条件
建议先准备好这些条件:
- 一个可管理的域名,能进入 DNS 服务商控制台添加、修改、删除记录。
- 一台已经能通过 IP 访问的入口服务器、负载均衡或 CDN 回源地址。
- 服务器上有 Nginx 或等价入口进程,至少能监听 80 / 443 或测试端口。
- 本地和服务器上具备
dig、nslookup、curl、openssl、ss这类验证工具。 - 如果部署在中国大陆公网,先确认域名备案、接入备案和云厂商域名接入要求;如果是企业内网,先确认内部 DNS 和客户端信任链。
先用一句话说清楚域名访问
很多人第一次部署网站时,会以为“买了域名,再填一个 IP,就能访问了”。真正上线时才发现:解析看起来成功了,浏览器还是打不开;HTTP 能访问,HTTPS 又报证书错误;自己电脑正常,用户那边还是旧页面;接了 CDN 后,源站日志里全是 CDN 节点 IP。
所以域名不是一个单独配置项,它是一条链路:
用户浏览器
-> 本机 hosts / DNS 缓存
-> 递归 DNS
-> 权威 DNS
-> 公网入口 / CDN / 负载均衡
-> Nginx server_name
-> 后端服务
-> HTTPS 证书校验这里要注意,DNS 只负责“把名字指到哪里”,它不负责判断你的 Nginx 是否配置正确,也不负责判断证书是否匹配。一个域名访问失败,至少要分四步看:
第一步:域名解析到了哪个入口?
第二步:入口的 80/443 端口通不通?
第三步:Nginx 是否按 Host 匹配到了正确 server?
第四步:HTTPS 证书是否覆盖这个域名?后面所有命令都围绕这四个问题展开。不要一上来就改 DNS,也不要一上来就重启 Nginx,先把现象定位到哪一层。
准备一个最小可验证环境
为了讲清楚,我们先约定几个示例值:
域名:example.com
主站:www.example.com
接口:api.example.com
新服务器公网 IPv4:203.0.113.20
旧服务器公网 IPv4:203.0.113.10
后端服务端口:127.0.0.1:8080生产环境里把这些值换成自己的即可。这里用 203.0.113.0/24 这类示例地址,是为了避免误导读者去访问真实机器。
如果你现在手里有一台 Linux 服务器,先看服务有没有跑起来:
curl -I http://127.0.0.1:8080正常情况下,应该看到类似:
HTTP/1.1 200 OK如果这里都不通,说明后端服务还没准备好,先不要急着配域名。域名只能把流量带到入口,不能把一个没启动的服务变成可访问。
再看服务器有没有监听 80 和 443:
sudo ss -lntp | grep -E ':80|:443'你应该能看到 Nginx 或其它入口进程监听端口。如果没有输出,一般有三种情况:
- Nginx 没启动。
- Nginx 配置错了,启动失败。
- 服务监听了别的端口。
先用下面命令检查:
sudo nginx -t
sudo systemctl status nginx --no-pagernginx -t 显示 syntax is ok 和 test is successful,只能说明配置语法没问题,不代表域名已经能访问。域名访问还要继续看 DNS、端口、安全组和证书。
域名、DNS 和服务器到底是什么关系
可以把域名理解成门牌号,把 DNS 理解成门牌号查询系统,把服务器 IP 理解成真实地址。
用户访问:
https://api.example.com浏览器不会天生知道 api.example.com 在哪里,它要先问 DNS。DNS 返回 IP 后,浏览器才会连接这个 IP 的 443 端口。到了服务器这一侧,Nginx 再根据请求里的 Host,也就是 api.example.com,选择对应的 server 配置。
这就是为什么同一个 IP 可以挂多个域名:
server {
listen 80;
server_name api.example.com;
}
server {
listen 80;
server_name admin.example.com;
}两个域名可以解析到同一个 IP,但 Nginx 会按 Host 分流。反过来也要注意:如果 DNS 已经解析到服务器,但 Nginx 没有写 server_name api.example.com,请求就可能落到默认站点,看起来像“访问到了别人的页面”。
DNS 记录怎么选
DNS 控制台里会看到 A、AAAA、CNAME、TXT、MX 等记录。先不要背概念,直接按场景选。
A 记录:域名指向 IPv4
如果你有一台公网服务器,IP 是 203.0.113.20,想让 api.example.com 访问它,一般配置 A 记录:
主机记录:api
记录类型:A
记录值:203.0.113.20
TTL:600配置后用命令验证:
dig +short A api.example.com正常应该返回:
203.0.113.20如果没有返回,先检查三件事:
- 主机记录是不是填成了
api.example.com,导致实际变成api.example.com.example.com。 - 域名的 DNS 服务器是不是已经切到当前云解析厂商。
- 记录是不是刚改完,还在 TTL 缓存期内。
Windows 上也可以这样看:
nslookup -type=A api.example.com这里要注意,A 记录只适合固定 IPv4 入口。如果接入 CDN、对象存储或厂商负载均衡,对方通常会给你一个 CNAME 地址,这时不要强行填 A 记录。
AAAA 记录:域名指向 IPv6
AAAA 记录用于 IPv6:
主机记录:api
记录类型:AAAA
记录值:2001:db8::20
TTL:600验证命令:
dig +short AAAA api.example.com
curl -6 -I https://api.example.com如果 dig 能查到 AAAA,但 curl -6 超时,说明 IPv6 链路没有通。常见原因是:
- 服务器没有 IPv6 地址。
- 云安全组没有放通 IPv6 入站。
- Nginx 没有监听 IPv6。
- CDN 或负载均衡没有开 IPv6。
- 证书和 SNI 没问题,但网络层压根连不上。
生产建议是:没有完整验证 IPv6 访问链路前,不要随手加 AAAA。很多“部分用户访问慢”的问题,就是客户端优先尝试 IPv6,失败后才回退 IPv4。
CNAME 记录:域名指向另一个域名
接 CDN 或云服务时,经常不是让你填 IP,而是给你一个地址,例如:
vendor-cdn.example.net这时一般配置 CNAME:
主机记录:www
记录类型:CNAME
记录值:vendor-cdn.example.net
TTL:600验证:
dig www.example.com CNAME
dig www.example.com A第一条命令看 CNAME 链路,第二条命令看最终落到哪些 A 记录。这里要注意,CNAME 只是“再指向另一个名字”,最终仍然要变成 A 或 AAAA,浏览器才能连接。
CNAME 有几个常见坑:
- 同一个主机记录通常不能同时配置 CNAME 和 MX、TXT 等记录。
- 裸域
example.com配 CNAME 受标准约束,云厂商一般用 ALIAS、ANAME 或 CNAME Flattening 做类似能力。 - 接入 CDN 后,
dig看到的是 CDN 节点地址,不是源站 IP。 - 回源 Host 配错时,DNS 看起来正常,Nginx 仍然可能匹配到错误站点。
TXT 记录:做验证和邮件安全
TXT 记录不是给浏览器访问的,更多用于证明“这个域名归我控制”。
证书 DNS-01 验证时,经常要求你添加:
主机记录:_acme-challenge
记录类型:TXT
记录值:一串验证 token
TTL:600验证:
dig TXT _acme-challenge.example.com应该能看到那串 token。如果看不到,先别反复点证书申请,先查是不是记录名填错了。很多人会把 TXT 加到 example.com,但证书系统真正要查的是 _acme-challenge.example.com。
TXT 还常用于:
- 第三方平台域名归属验证。
- SPF。
- DKIM。
- DMARC。
如果是第三方平台要求放验证文件,也要注意它到底要求的是 TXT,还是要求在网站根目录放一个文件。这两类验证方式不是一回事。
MX 记录:给邮箱用
网站能访问,不代表邮箱能收信。邮箱要看 MX:
主机记录:@
记录类型:MX
记录值:10 mx1.example.net验证:
dig MX example.com如果公司邮箱收不到信,排查方向一般是 MX、SPF、DKIM、DMARC,不要只看 A 记录。这里最容易踩的是 CNAME 冲突:同一个主机记录上有 CNAME,再配 MX 或 TXT,经常会被 DNS 控制台拒绝,或者表现异常。
DNS 解析链路怎么查
现在我们配置了记录,但怎么知道它从哪里坏了?先看默认解析结果:
dig api.example.com A输出里重点看三块:
;; ANSWER SECTION:
api.example.com. 600 IN A 203.0.113.20ANSWER SECTION 里有正确 IP,说明当前递归 DNS 查到了记录。中间那个 600 是 TTL,它表示这个结果还能缓存多久。
再换几个递归 DNS 看看:
dig @8.8.8.8 api.example.com A
dig @1.1.1.1 api.example.com A
dig @223.5.5.5 api.example.com A
dig @119.29.29.29 api.example.com A如果不同 DNS 返回不一样,不一定是你配置错了,可能是缓存还没过期。生产切换时不要只看自己电脑,因为你电脑用的是某一个递归 DNS,用户可能用的是另一个。
把解析过程拆开看,链路大概是这样:
这张图排障时很好用:浏览器命中旧值,就查本机缓存、hosts 和浏览器缓存;递归 DNS 命中旧值,就换多个递归 DNS 对比;权威 DNS 还是旧值,才回到 DNS 控制台检查记录;CNAME 后没有最终 A / AAAA,就继续追目标域名。最后已经拿到正确 IP 但访问失败,问题就不在 DNS,而要转去查端口、安全组、SNI、证书和 Nginx server_name。
想看权威链路,用:
dig +trace api.example.com A这个命令会从根、顶级域、权威 DNS 一路追下去。它解决的问题是:到底是权威 DNS 本身没改对,还是递归 DNS 缓存没刷新。
如果想直接查权威 DNS,先看 NS:
dig NS example.com假设返回:
ns1.example-dns.net.
ns2.example-dns.net.再查:
dig @ns1.example-dns.net api.example.com A如果权威 DNS 已经返回新 IP,但递归 DNS 还返回旧 IP,大概率就是缓存问题。这个时候继续修改记录通常没有意义,反而会把现场搞乱。
TTL:为什么改了 DNS 还没生效
TTL 可以理解为“这条记录允许别人缓存多久”。如果你把 TTL 设成 3600,很多递归 DNS 查到后就可能缓存 1 小时。
这里要注意,TTL 不是立即生效按钮。你现在把 TTL 从 3600 改成 60,并不能让已经缓存了 3600 的递归 DNS 立刻忘掉旧结果。
生产切换建议这样做:
T-24h 或至少 T-2h:把 TTL 降到 300 或云厂商允许的最低值
T-10min:确认权威 DNS 返回低 TTL
T:修改 A / CNAME 到新入口
T+5min:多递归 DNS、多地区、多客户端验证
稳定后:把 TTL 调回 600 / 1800 / 3600验证 TTL:
dig api.example.com A你会看到类似:
api.example.com. 287 IN A 203.0.113.20这里的 287 表示当前递归 DNS 缓存里还剩 287 秒。不同递归 DNS 看到的 TTL 不一样很正常,因为它们缓存的时间点不同。
一般生产切换前,我会把旧值、新值、TTL 和回滚值写在一张表里:
| 项目 | 旧值 | 新值 | 验证方式 |
|---|---|---|---|
| 记录名 | api.example.com | api.example.com | dig |
| 记录类型 | A | A / CNAME | 控制台、dig |
| 记录值 | 203.0.113.10 | 203.0.113.20 | curl --resolve |
| TTL | 3600 | 300 | dig |
这么做的好处是,切换现场不会靠记忆操作。出问题时也知道要回滚到哪个值。
hosts:临时验证新入口很好用,但别长期靠它
hosts 是本机静态解析,优先级通常高于 DNS。它适合上线前验证新服务器。
Linux / macOS:
/etc/hostsWindows:
C:\Windows\System32\drivers\etc\hosts加一行:
203.0.113.20 api.example.com然后访问:
curl -I http://api.example.com
curl -Iv https://api.example.com如果是 Windows,可以查看和刷新 DNS 缓存:
ipconfig /displaydns
ipconfig /flushdns这里要注意,hosts 只影响本机。你自己访问正常,不代表用户正常。更麻烦的是,很多线上事故排查到最后,发现是某个同学几天前改过 hosts 忘了删。
比改 hosts 更推荐的是 curl --resolve:
curl --resolve api.example.com:443:203.0.113.20 https://api.example.com/health -Iv这个命令的意思是:只在这一次请求里,把 api.example.com:443 临时解析到 203.0.113.20,同时保留 HTTPS 的 SNI 和 Host。它非常适合在 DNS 正式切换前验证新入口。
正常应该看到:
HTTP/2 200如果这里报证书不匹配,说明新入口上的证书没有覆盖 api.example.com。如果这里连接超时,先查安全组、防火墙和 Nginx 监听。
中国大陆公网先看备案和端口
如果域名解析到中国大陆服务器、负载均衡、CDN 或 WAF,先确认备案和接入要求。这个不是 Nginx 能解决的问题。
一般需要检查:
- 域名是否完成 ICP 备案。
- 当前云厂商是否要求接入备案。
- 80 和 443 是否在安全组里放通。
- 系统防火墙是否放通。
- 证书申请方式是否能走通。
先查 DNS:
dig +short A www.example.com再查端口:
curl -I http://www.example.com
curl -Iv https://www.example.com服务器上看监听:
sudo ss -lntp | grep -E ':80|:443'如果使用 firewalld:
sudo firewall-cmd --list-all
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload如果使用 ufw:
sudo ufw status
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp这里要注意,云安全组和系统防火墙是两层。本机 curl http://127.0.0.1 正常,只能说明服务在本机可用,不代表公网能访问。
常见现象可以这样判断:
| 现象 | 优先看哪里 |
|---|---|
| 本机正常,公网超时 | 云安全组、系统防火墙、公网 IP |
| HTTP 正常,HTTPS 失败 | 443 监听、证书、Nginx SSL 配置 |
| 证书 HTTP-01 验证失败 | 80 端口、备案接入、CDN/WAF 是否拦截 |
| 解析正确但访问被云厂商提示 | 备案或接入状态 |
非标准端口不能当作备案规避方案。只要是面向中国大陆公网提供 Web 服务,就按云厂商和监管要求处理。
企业内网和离线环境怎么做
内网不要长期靠每台机器改 hosts。刚开始联调可以这么做,真正进入团队使用后,最好有内部 DNS。
一种常见做法:
app.corp.example.com -> 10.0.0.20
api.corp.example.com -> 10.0.0.21验证:
dig @10.0.0.2 api.corp.example.com A
curl -I http://api.corp.example.com如果公司有多个网络区域,比如办公网、服务器网、容器网、VPN 网,要分别验证。内网 DNS 的坑经常是:办公电脑能解析,服务器不能解析;宿主机能解析,容器不能解析。
Docker 容器里要看自己的解析配置:
docker exec -it app sh
cat /etc/resolv.conf
cat /etc/hosts
nslookup api.corp.example.com
getent hosts api.corp.example.com如果容器里解析失败,可以在 Docker daemon 里指定 DNS:
{
"dns": ["10.0.0.2", "10.0.0.3"]
}或者启动容器时指定:
docker run --dns 10.0.0.2 --dns-search corp.example.com nginx:stable离线环境还要多准备一层证书和工具。一般需要提前准备:
- 内部 DNS 或静态解析方案。
- 内部 CA 根证书。
- 站点证书和私钥。
- Nginx、OpenSSL、curl、dig/nslookup 等排障工具。
- 证书续期和分发流程。
- 域名、IP、端口、回滚值清单。
离线环境最怕“某个人机器上能访问”。交付时要把 DNS、证书、Nginx、客户端信任根证书都纳入验收。
把域名接到 Nginx
DNS 解析到服务器后,Nginx 要按 Host 接住请求。先写一个最小配置:
server {
listen 80;
server_name api.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;
}
}保存后检查:
sudo nginx -t看到 test is successful 后再 reload:
sudo systemctl reload nginx然后直接用 IP 加 Host 验证:
curl -I -H 'Host: api.example.com' http://203.0.113.20这个命令解决的问题是:不依赖 DNS,直接验证 Nginx 是否能按 api.example.com 这个 Host 匹配到正确站点。
如果返回的是另一个系统,常见原因是:
server_name没写api.example.com。- 配置文件没有被主配置 include。
- 多个 server block 重复配置了同一个域名。
- 请求落到了默认 server。
可以看完整配置:
sudo nginx -T | grep -n "server_name"再看日志:
sudo tail -f /var/log/nginx/access.log /var/log/nginx/error.log生产上建议给默认 server 一个明确处理方式,不要误返回其它业务:
server {
listen 80 default_server;
server_name _;
return 444;
}如果要把裸域跳到 www:
server {
listen 80;
server_name example.com;
return 301 https://www.example.com$request_uri;
}这里要注意,301 是永久跳转,浏览器和搜索引擎都会缓存。生产前先确认方向,不要今天跳 www,明天又跳回裸域。
把域名接到 HTTPS 证书
HTTPS 比 HTTP 多一个关键动作:浏览器会检查证书是否属于当前访问域名。
访问:
https://api.example.com证书里就必须包含:
api.example.com现在主要看证书的 SAN,不要再只看 Common Name。
查看线上证书:
openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName重点看:
notBefore
notAfter
X509v3 Subject Alternative Name如果 SAN 里没有 api.example.com,浏览器就会提示证书域名不匹配。DNS 再正确也没用。
Nginx HTTPS 最小配置:
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/nginx/certs/api.example.com/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/api.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
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 https;
}
}HTTP 跳 HTTPS:
server {
listen 80;
server_name api.example.com;
return 301 https://$host$request_uri;
}检查并重载:
sudo nginx -t
sudo systemctl reload nginx
curl -Iv https://api.example.com常见错误这样看:
| 现象 | 常见原因 | 怎么确认 |
|---|---|---|
| 证书域名不匹配 | SAN 不包含访问域名 | openssl s_client |
| 证书过期 | 续期失败或 reload 漏了 | 看 notAfter |
| 部分客户端不信任 | 中间证书链不完整 | 用 fullchain.pem |
| Nginx 启动失败 | 证书和私钥不匹配 | nginx -t 和 error log |
| CDN 正常、源站异常 | 边缘证书和源站证书不是同一套 | 分别查 CDN 和源站 |
截至 2026-07-09,公开 TLS 证书的有效期要求已经在继续收紧。生产上不要把“一年一换证书”当成稳定假设,应该把自动续期、续期告警和 reload 验证做进运维流程。
HTTP-01 和 DNS-01 怎么选
申请证书时,CA 要验证你确实控制这个域名。常用两种方式。
HTTP-01 要求 CA 能访问:
http://api.example.com/.well-known/acme-challenge/<token>适合:
- 域名已经解析到当前服务器。
- 80 端口公网可达。
- 中间没有 CDN/WAF 拦截验证路径。
验证思路很简单,你自己先访问:
curl -I http://api.example.com/.well-known/acme-challenge/test如果 80 端口都访问不了,HTTP-01 大概率会失败。
DNS-01 要求添加 TXT:
_acme-challenge.api.example.com验证:
dig TXT _acme-challenge.api.example.comDNS-01 适合:
- 泛域名证书。
- 内网服务。
- 服务器没有公网入口。
- 80 端口不能开放。
- 证书申请机和业务服务器不是同一台。
这里要注意,DNS-01 最好接 DNS 厂商 API 自动化。人工复制 TXT 能用,但续期时很容易漏掉,尤其是证书有效期越来越短以后。
泛域名:DNS 泛解析和证书泛域名不是一回事
DNS 泛解析是:
*.example.com A 203.0.113.20它解决的是:a.example.com、b.example.com 这类子域名都能解析到入口。
证书泛域名是:
*.example.com它解决的是:这些子域名访问 HTTPS 时证书能匹配。
两者要分别配置。只配 DNS 泛解析,没有泛域名证书,HTTPS 还是会报错。只配泛域名证书,没有 DNS 解析,浏览器连服务器都找不到。
还有一个很常见的坑:
*.example.com一般覆盖 api.example.com,不覆盖裸域 example.com。如果裸域也要访问,证书里通常要同时包含:
example.com
*.example.comNginx 也要接住:
server {
listen 443 ssl http2;
server_name *.example.com;
ssl_certificate /etc/nginx/certs/example.com/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
}
}生产建议是:泛域名可以减少配置,但不要把它当权限隔离。多租户、管理后台、测试环境最好仍然有明确域名规则和访问控制。
CDN 接入后,排障要拆成两段
不接 CDN 时,用户大致是:
用户 -> 源站 Nginx接 CDN 后变成:
用户 -> CDN 边缘节点 -> 源站 Nginx所以排障也要拆成两段。先验证源站:
curl --resolve www.example.com:443:203.0.113.20 https://www.example.com -Iv这条命令绕过 CDN,直接打源站,同时保留 Host 和 SNI。源站如果不正常,不要先怪 CDN。
再验证 CDN:
dig www.example.com CNAME
curl -Iv https://www.example.com如果 dig 返回的是 CDN 厂商域名或 CDN 节点 IP,说明流量已经走 CDN。
这里要注意几个边界:
- DNS-only 返回源站或负载均衡地址。
- 代理模式返回 CDN 节点地址。
- 浏览器看到的是 CDN 边缘证书。
- CDN 回源时还要看回源协议、回源 Host、回源端口和源站证书。
- 源站日志里看到的客户端 IP 可能是 CDN IP。
Nginx 里一般要保留这些头:
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;如果要拿真实客户端 IP,按 CDN 厂商文档配置可信代理 IP 段和真实 IP 头。不要无条件信任客户端自己传来的 X-Forwarded-For。
常见 CDN 问题:
| 现象 | 优先看哪里 |
|---|---|
| CDN 返回 502 | 回源地址、源站端口、源站证书、源站日志 |
| 用户看到旧内容 | CDN 缓存规则、刷新预热 |
| HTTPS 边缘正常但回源失败 | CDN 回源协议和源站证书 |
| 源站限流误伤 | 真实 IP 配置和 CDN IP 段 |
生产解析切换怎么做
生产切换不要临场发挥。建议按下面步骤走。
第一步,提前降低 TTL:
api.example.com A 203.0.113.10 TTL=300这里的重点是提前。旧 TTL 如果是 3600,就至少提前一个旧 TTL 周期处理。
第二步,验证新入口,不改 DNS:
curl --resolve api.example.com:443:203.0.113.20 https://api.example.com/health -Iv
curl --resolve api.example.com:443:203.0.113.20 https://api.example.com/api/version应该看到健康检查 200,证书也应该匹配 api.example.com。
第三步,切换 DNS:
api.example.com A 203.0.113.20 TTL=300第四步,多递归 DNS 验证:
dig api.example.com A
dig @8.8.8.8 api.example.com A
dig @1.1.1.1 api.example.com A
dig @223.5.5.5 api.example.com A第五步,观察入口日志:
sudo tail -f /var/log/nginx/access.log /var/log/nginx/error.log切换完成后不要马上释放旧服务器。至少保留一个旧 TTL 周期以上,因为还有递归 DNS、客户端缓存、CDN 回源缓存和长连接。
把上面的动作放到变更评审里,可以按这张图走:
这张图的价值不在于“切换步骤更多”,而是把回滚条件提前说清楚。评审时至少要问四个问题:旧 TTL 是否已经降完并等待生效,新入口是否能用 curl --resolve 绕过 DNS 访问,灰度解析能力是否真实可用,回滚后旧入口要保留多久。只要缓存窗口还没过去,监控就必须同时看新旧入口,否则很容易把“部分用户还在访问旧 IP”误判成新版本异常。
DNS 回滚怎么做
回滚前先判断问题在哪一层:
- 新 Nginx 配错了,优先回滚 Nginx 配置。
- 新后端版本有问题,优先回滚业务版本。
- 新入口 IP 不通,再回滚 DNS。
- 证书错了,优先替换证书并 reload。
- CDN 缓存错了,先刷新缓存或临时绕开 CDN 验证源站。
如果确认要回滚 DNS,把记录改回旧值:
api.example.com A 203.0.113.10然后验证:
dig api.example.com A
curl --resolve api.example.com:443:203.0.113.10 https://api.example.com/health -Iv
curl -Iv https://api.example.com/health这里要注意,DNS 回滚也不是立即全网恢复。旧入口必须继续保留,直到缓存自然消退。
生产经验是:切换当天不要做“顺手清理”。旧证书、旧安全组、旧 Nginx 配置、旧机器都先保留。等监控稳定、日志稳定、投诉归零,再进入清理窗口。
常见故障一条条排
解析没生效
现象:
控制台已经改了记录,但用户还访问旧 IP。先查默认 DNS:
dig api.example.com A再查公共 DNS:
dig @8.8.8.8 api.example.com A
dig @1.1.1.1 api.example.com A
dig @223.5.5.5 api.example.com A再查权威链路:
dig +trace api.example.com A如果权威已经是新值,递归还是旧值,等 TTL。不要来回修改。 如果权威还是旧值,说明控制台记录、DNS 服务商或 NS 配置就有问题。
还要检查本机有没有 hosts:
getent hosts api.example.comWindows 看:
ipconfig /displaydns
ipconfig /flushdns访问到了错误站点
现象:
DNS 指向了正确服务器,但页面显示另一个系统。直接用 Host 打服务器:
curl -I -H 'Host: api.example.com' http://203.0.113.20检查 Nginx:
sudo nginx -T | grep -n "server_name"常见原因:
server_name漏了域名。- 默认 server 抢了请求。
- 多个配置文件重复匹配。
- CDN 回源 Host 写错。
解决后:
sudo nginx -t
sudo systemctl reload nginxHTTPS 证书域名不匹配
现象:
浏览器提示证书不是颁发给当前域名。查看证书:
openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName如果 SAN 里没有 api.example.com,重新签发证书。 如果证书正确但浏览器还是报错,检查是不是 CDN 边缘证书还没更新,或者 Nginx SNI 匹配到了另一个 server。
只有部分用户异常
现象:
公司网络正常,手机流量异常;国内正常,海外异常;部分地区还在旧 IP。先对比不同 DNS:
dig @223.5.5.5 api.example.com A
dig @119.29.29.29 api.example.com A
dig @8.8.8.8 api.example.com A
dig @1.1.1.1 api.example.com A再看有没有 AAAA:
dig AAAA api.example.com很多“部分用户慢”是 IPv6 异常。没有完整 IPv6 链路时,先移除 AAAA 记录再观察。
如果怀疑 CDN 调度问题,看 CDN 控制台里的地区、运营商和节点日志。不要只凭一张用户截图判断。
DNS 污染、劫持或异常缓存
现象:
某些网络把域名解析到陌生 IP、广告页或运营商提示页。先收证据:
nslookup api.example.com
nslookup api.example.com 8.8.8.8
nslookup api.example.com 1.1.1.1
dig +trace api.example.com同时记录:
- 用户所在地区和运营商。
- 用户使用的 DNS。
- 实际解析到的 IP。
- 访问时间。
- HTTPS 证书信息。
- 响应头和页面截图。
只有权威 DNS 正确、公共 DNS 正常、某个网络异常时,才更像本地网络或运营商侧问题。排障时先拿证据,不要一句“被污染了”就结束。
CNAME 后 TXT 或 MX 配不上
现象:
已经配置 CNAME,同名 TXT / MX 添加失败。这个通常是记录冲突。处理方式是拆域名:
- Web 用
www.example.com或app.example.com。 - 邮箱放在
example.com的 MX。 - 证书验证按
_acme-challenge加 TXT。 - 裸域需要类似 CNAME 的能力时,看云 DNS 是否支持 ALIAS、ANAME 或 CNAME Flattening。
不要把所有东西都塞到同一个主机记录上。
DNS-01 证书验证失败
现象:
ACME 客户端提示 TXT 不存在或值不匹配。先查 TXT:
dig TXT _acme-challenge.example.com
dig @8.8.8.8 TXT _acme-challenge.example.com
dig +trace _acme-challenge.example.com TXT常见原因:
- TXT 名称填错。
- TXT 值复制时多了空格。
- 云解析 API token 权限不足。
- 同时申请多个域名,需要多个 TXT 值。
- TTL 缓存未过期。
自动续期前,一定要先在测试域名演练。证书不是签下来就结束,还要验证 reload 后线上拿到的是新证书。
容器里解析失败
现象:
宿主机能解析,容器里解析失败。进入容器:
docker exec -it app sh
cat /etc/resolv.conf
cat /etc/hosts
nslookup api.example.com
getent hosts api.example.com如果容器里没有 nslookup,临时装工具或使用带网络工具的排障镜像。生产镜像可以保持精简,但排障环境要提前准备。
常见原因:
- Docker daemon DNS 配置不对。
- 容器网络访问不到内网 DNS。
dns-search没配。- 企业 DNS 只允许特定网段访问。
不要假设宿主机能解析,容器就一定能解析。
落地工程深水区
DNS 的深水区不在“添加一条 A 记录”,而在变更窗口、缓存不可控、跨团队协作和回滚。DNS 变更一旦扩散,很多问题不是立刻能撤回的。
| 深水问题 | 现场表现 | 落地约束 |
|---|---|---|
| TTL 没提前治理 | 切换后部分用户还访问旧入口,回滚也慢 | 生产切换前提前一个 TTL 周期降低记录 TTL,切换后等稳定再恢复 |
| CNAME 冲突 | 邮件 TXT、MX、域名验证和 CDN CNAME 互相冲突 | 同一主机名规划清楚记录类型;根域优先看 DNS 服务商是否支持 ALIAS / CNAME flattening |
| 解析和证书不同步 | DNS 指到新域名,但证书 SAN 没覆盖,HTTPS 报错 | 域名变更清单必须同时检查解析、Nginx server_name、证书 SAN 和 CDN 边缘证书 |
| 内网和公网分裂 | 办公网正常,公网用户异常,或容器内解析到另一套地址 | 明确 split-horizon DNS 策略,容器、服务器、办公终端分别验证解析结果 |
| CDN 掩盖源站问题 | 用户异常但源站日志看不到,或者只看到 CDN 节点 IP | 排障按“客户端到 CDN”和“CDN 到源站”分段,保留回源 Host、协议、缓存规则和真实 IP 头 |
| DNS 权限过大 | 证书自动化 token 能改整片域名区,泄露后风险巨大 | DNS API token 最小权限,只允许写 _acme-challenge 或指定记录,定期轮换 |
| 回滚只回 DNS | 应用、Nginx、证书、CDN 缓存仍处于新版本状态 | DNS 回滚、入口配置回滚、CDN 刷新、证书回滚和应用回滚要写成同一张变更单 |
域名切换要按发布流程做:发布前验证新入口,发布中观察递归 DNS、源站日志和业务指标,发布后保留旧入口至少一个 TTL 周期。不要把 DNS 当成“改个值”的轻操作。
上线前检查清单
- 域名已经购买、实名、可管理。
- 中国大陆公网服务已经完成备案和接入要求。
- A / AAAA / CNAME / TXT / MX 没有冲突。
- 切换前已经提前降低 TTL。
- 权威 DNS 查询结果正确。
- 多个递归 DNS 查询结果符合预期。
- 新入口安全组和系统防火墙已放通。
- Nginx
server_name覆盖所有访问域名。 - 默认 server 不会误返回其它业务站点。
- HTTPS 证书 SAN 覆盖裸域、
www、API 域名和必要泛域名。 - 证书链完整,私钥权限正确。
- CDN 场景已验证边缘证书、回源 Host、回源协议和缓存规则。
- 内网场景已验证内部 DNS、客户端信任 CA、容器 DNS。
- 旧解析值、旧入口、旧证书和回滚步骤都已准备。
- 切换后有日志、状态码、错误率、延迟和业务功能验证。
常用命令速查
DNS:
dig A api.example.com
dig AAAA api.example.com
dig CNAME www.example.com
dig TXT _acme-challenge.example.com
dig MX example.com
dig +trace api.example.com A
dig @8.8.8.8 api.example.com AWindows:
nslookup -type=A api.example.com
nslookup -type=TXT _acme-challenge.example.com
ipconfig /displaydns
ipconfig /flushdnsHTTP / HTTPS:
curl -I http://api.example.com
curl -Iv https://api.example.com
curl -I -H 'Host: api.example.com' http://203.0.113.20
curl --resolve api.example.com:443:203.0.113.20 https://api.example.com -Iv证书:
openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null
openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltNameNginx:
sudo nginx -t
sudo nginx -T
sudo systemctl reload nginx
sudo ss -lntp | grep -E ':80|:443'
sudo tail -f /var/log/nginx/access.log /var/log/nginx/error.log容器:
docker exec -it app sh
cat /etc/resolv.conf
cat /etc/hosts
nslookup api.example.com
getent hosts api.example.com官方校准入口
这些入口用于落地时校准最新规则和厂商差异:
- Cloudflare DNS 记录类型:https://developers.cloudflare.com/dns/manage-dns-records/reference/dns-record-types/
- RFC 1034 DNS 概念与 TTL 语义:https://datatracker.ietf.org/doc/html/rfc1034
- RFC 1035 DNS 实现、A / CNAME / MX / TXT 等记录格式:https://datatracker.ietf.org/doc/html/rfc1035
- RFC 3596 AAAA 记录:https://datatracker.ietf.org/doc/html/rfc3596
- RFC 8659 CAA 记录:https://datatracker.ietf.org/doc/html/rfc8659
- RFC 1912 DNS 常见运维配置错误:https://datatracker.ietf.org/doc/html/rfc1912
- ICANN Root Server System:https://www.icann.org/en/system/files/files/root-server-system-infographic-23dec24-en.pdf
- Cloudflare 代理状态和 DNS-only 边界:https://developers.cloudflare.com/dns/proxy-status/
- Cloudflare Wildcard DNS:https://developers.cloudflare.com/dns/manage-dns-records/reference/wildcard-dns-records/
- 阿里云云解析记录添加说明:https://help.aliyun.com/zh/dns/pubz-add-parsing-record
- 腾讯云 DNSPod CNAME Flattening:https://cloud.tencent.com/document/product/302/115536
- BIND
dig手册:https://bind9.readthedocs.io/en/stable/manpages.html - Microsoft
nslookup:https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/nslookup - Microsoft
ipconfig:https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/ipconfig - Nginx
server_name:https://nginx.org/en/docs/http/server_names.html - Nginx 请求处理:https://nginx.org/en/docs/http/request_processing.html
- Nginx HTTPS 配置:https://nginx.org/en/docs/http/configuring_https_servers.html
- Let’s Encrypt Challenge Types:https://letsencrypt.org/docs/challenge-types/
- Certbot 使用文档:https://eff-certbot.readthedocs.io/en/stable/using.html
- CA/B Forum Baseline Requirements:https://cabforum.org/working-groups/server/baseline-requirements/requirements/
- RFC 9525:https://www.rfc-editor.org/info/rfc9525/
- 工信部 ICP/IP 地址/域名信息备案管理系统:https://beian.miit.gov.cn/
最后一条经验
域名问题最折磨人的地方,不是命令复杂,而是链路太长。DNS、Nginx、证书、CDN、备案、安全组、浏览器缓存,每一层都可能“看起来正常”,合起来却访问失败。
真正靠谱的做法是把域名变更当成一次发布:提前降 TTL,用 curl --resolve 验证新入口,检查证书 SAN,确认 Nginx Host 匹配,观察日志,准备 DNS 和配置双回滚。这样即使缓存不可控,人的操作也能尽量可控。
