排错指南

泛域名证书为什么不覆盖主域名

子域名都正常,直接访问主域名却报证书错误。

*.example.com 覆盖 www.example.comapi.example.comshop.example.com,但不覆盖 example.com 本身。这不是某家 CA 的限制,是通配符证书的匹配规则(RFC 6125):通配符只能出现在最左边的那一段,而且只匹配一段

所以典型症状是:所有子域名都好,唯独直接访问主域名报证书错误。看起来像 DNS 出了问题,实际是证书少签了一个名字。解决办法是把 example.com*.example.com 一起签进同一张证书。

匹配规则:一颗星等于一段

证书里写的访问的域名是否匹配
*.example.comwww.example.com
*.example.comapi.example.com
*.example.comexample.com❌ 主域名不是它的子域名
*.example.coma.b.example.com❌ 一颗星只匹配一段
*.b.example.coma.b.example.com
www.*.com任何域名❌ 通配符只能在最左段
*.com任何域名❌ 公共后缀上不签发通配符

顺带说一个容易被忽略的点:现在的浏览器只看 SAN(Subject Alternative Name)列表,证书里的 CN 字段自 Chrome 58 起就被忽略了。所以「CN 写的是 example.com,应该能用」这个判断不成立 —— 域名必须出现在 SAN 里。

为什么 301 跳转救不了

很多人第一反应是「我在服务器上把 example.com 跳到 www 就行了」。这条路走不通,原因是顺序:

  1. 浏览器先和 example.com 建立 TLS 连接。
  2. 服务器发来一张不包含 example.com 的证书。
  3. 浏览器在这里就中止了,并显示证书错误。
  4. 你写的那条 301 在 HTTP 层,属于第 4 步 —— 永远轮不到它执行。

换句话说,只要你希望访客能输入 example.com 打开你的网站(哪怕只是为了跳转到 www),这张证书就必须包含 example.com

怎么看自己的证书覆盖了哪些域名

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -ext subjectAltName

# X509v3 Subject Alternative Name:
#     DNS:*.example.com, DNS:example.com

上面这个输出是正确的样子 —— 两个名字都在。如果只有 DNS:*.example.com 一个,那就是本文说的情况。

本站的证书检测会列出完整的 SAN 列表,并在只有泛域名、缺主域名时单独指出来。它只针对你查的那个域名报这个问题,不会把同一张证书上别人家的域名也算进来。

正确的签法

把两个名字签进同一张证书。不需要两张证书,也不需要额外费用:

# 一张证书,两个 SAN
example.com
*.example.com

在本站免费签发时这是默认行为 —— 勾选泛域名,基础域名会一起签进去,正是因为这个坑太常见。用 certbot 的话,两个名字都要写出来:

certbot certonly --manual --preferred-challenges dns \
  -d example.com -d '*.example.com'

泛域名证书只能用 DNS-01 验证,HTTP 文件验证不被接受 —— 这是 ACME 协议的规定,不是我们的限制。两个名字会各自需要一条 TXT 记录,记录名相同(_acme-challenge.example.com),值不同,两条要同时存在。

多级子域名怎么办

a.b.example.com 需要 *.b.example.com*.example.com 覆盖不到它。层级多的时候,把每一层的通配符都签进同一张证书:

example.com
*.example.com
*.b.example.com

常见问题

检测一下你自己的域名

免登录,一次真实的 TLS 握手,直接给出结论:还有多少天到期、证书链是否完整、是否包含这个域名。

需要一张新证书?本站提供基于 Let's Encrypt 的免费签发,支持泛域名。

了解免费证书

其他排错指南

Last updated on