HTTPS 证书基础:为什么子域名不能复用主域名证书
从「阿里云免费证书不能复用到
kb子域名」讲起:SAN、DV / OV / EV、Let's Encrypt + ACME、HTTP-01 / DNS-01,以及 Certbot 与 Nginx 的证书配置。
示例域名统一使用 kb.example.com,主域名使用 example.com。本文是 生产部署记录 第 10、12.3 节的展开。
一、为什么需要 HTTPS 证书
HTTP 是明文传输。用户输入的密码、模型 API Key、聊天内容,在网络中都可能被看到或篡改。
HTTPS = HTTP + TLS(传输层安全协议)。TLS 做了三件事:
| 能力 | 说明 |
|---|---|
| 加密 | 数据在传输中被加密,中间人看不到内容 |
| 完整性 | 数据被修改会被发现 |
| 身份验证 | 证明你连接的服务器确实是 kb.example.com |
证书(Certificate) 就是「身份验证」这一部分的凭证:它证明「这个公钥属于这个域名」。
二、证书里有什么
一张 TLS 证书主要包含:
- 域名信息:证书适用于哪些域名
- 公钥:客户端用来加密、验证的密钥
- 颁发者(Issuer):谁签发的,例如 Let's Encrypt、DigiCert
- 有效期:开始时间和过期时间
- 签名:由上级 CA(证书颁发机构)签名,证明证书可信
查看证书:
openssl s_client -connect kb.example.com:443 -servername kb.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
会看到类似输出:
subject=CN=kb.example.com
issuer=C=US, O=Let's Encrypt, CN=...
notBefore=...
notAfter=...
X509v3 Subject Alternative Name:
DNS:kb.example.com
重点看 Subject Alternative Name(SAN):现代浏览器只认 SAN 里的域名,不再只看 CN。
三、证书的关键概念
3.1 CA:证书颁发机构
CA 是浏览器和操作系统信任的「公证机构」。
信任链大致是:
根证书(内置在浏览器/系统中)
└─ 中间证书(CA 签发)
└─ 你的服务器证书(kb.example.com)
浏览器会逐级验证签名,只要链上有一环不被信任,就会报错。
3.2 证书类型:DV / OV / EV
| 类型 | 验证内容 | 价格 | 典型用途 |
|---|---|---|---|
| DV(域名验证) | 只验证你能控制这个域名 | 免费或便宜 | 个人项目、博客、普通网站 |
| OV(组织验证) | 验证公司/组织身份 | 较贵 | 企业官网 |
| EV(扩展验证) | 更严格的组织审核 | 最贵 | 金融、大型企业(现在浏览器地址栏已不明显展示) |
阿里云免费证书通常是 DV 单域名证书。
3.3 证书覆盖范围:单域名 / 多域名 / 通配符
| 类型 | 示例 | 能覆盖 |
|---|---|---|
| 单域名 | kb.example.com | 只能用于这一个域名 |
| 多域名(SAN) | example.com、www.example.com | 列表里的几个域名 |
| 通配符 | *.example.com | 所有一级子域名,如 kb、api、blog |
通配符
*.example.com不包含example.com本身,也不包含a.b.example.com这种二级子域名。
四、为什么阿里云免费证书不能复用到 kb 子域名
假设你现在的证书是:
SAN: example.com, www.example.com
访问 kb.example.com 时,浏览器检查:
请求的域名 kb.example.com 是否在证书 SAN 列表里?
答案是否定的,于是报证书不匹配错误。
所以解决方法只有三种:
- 为
kb.example.com单独申请一张证书(最简单,本项目采用) - 购买/申请通配符证书
*.example.com,覆盖所有子域名 - 把应用放到已有域名的路径下,例如
https://www.example.com/kb/(需要改应用的路径配置,较麻烦)
生产部署采用第 1 种。
五、Let's Encrypt 与 ACME:为什么它能免费
Let's Encrypt 是一个免费、自动化的 CA。
它的特点:
- 证书免费
- 有效期只有 90 天
- 鼓励自动续期
- 通过 ACME 协议 自动完成域名验证和签发
ACME(Automatic Certificate Management Environment) 是一套自动化协议,让客户端(如 Certbot)可以自动完成:
注册账号 → 申请证书 → 证明域名归你所有 → 下载证书 → 续期
六、域名验证方式:HTTP-01 与 DNS-01
Let's Encrypt 需要确认:「申请证书的人,真的控制这个域名。」
6.1 HTTP-01(本项目使用)
流程:
1. Certbot 向 Let's Encrypt 请求证书 kb.example.com
2. Let's Encrypt 返回一个随机 token
3. Certbot 在服务器上放一个文件:
http://kb.example.com/.well-known/acme-challenge/<token>
4. Let's Encrypt 从公网访问这个 URL
5. 内容一致 → 验证通过 → 签发证书
要求:
- 域名必须解析到你的服务器
- 80 端口必须能从公网访问
- 不能只申请通配符证书
6.2 DNS-01
流程:
Let's Encrypt 要求你在 DNS 中添加一条 TXT 记录:
_acme-challenge.example.com TXT "随机值"
适合:
- 申请 通配符证书
*.example.com - 服务器 80 端口不对外开放的场景
需要 DNS 服务商的 API 支持,自动化配置较复杂。
七、Certbot 在做什么
Certbot 是 Let's Encrypt 官方推荐的 ACME 客户端。
本项目执行的命令:
sudo certbot --nginx -d kb.example.com
分解来看:
| 部分 | 作用 |
|---|---|
certbot | 启动证书工具 |
--nginx | 使用 Nginx 插件,自动修改 Nginx 配置 |
-d kb.example.com | 申请这个域名的证书 |
执行后 Certbot 通常会:
- 完成 HTTP-01 域名验证
- 把证书保存到
/etc/letsencrypt/live/kb.example.com/ - 修改 Nginx 配置,添加
listen 443 ssl - 可选:把 HTTP 自动跳转到 HTTPS
- 配置定时任务自动续期
证书文件:
/etc/letsencrypt/live/kb.example.com/fullchain.pem # 证书 + 中间证书(Nginx 用这个)
/etc/letsencrypt/live/kb.example.com/privkey.pem # 私钥(绝对不能泄露)
八、Nginx 如何使用证书
Nginx 中的 HTTPS 配置大致如下:
server {
listen 443 ssl;
server_name kb.example.com;
# 证书链:服务器证书 + 中间证书
ssl_certificate /etc/letsencrypt/live/kb.example.com/fullchain.pem;
# 私钥
ssl_certificate_key /etc/letsencrypt/live/kb.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3001;
}
}
为什么用 fullchain.pem 而不是 cert.pem?
因为浏览器需要完整的信任链,缺少中间证书时,某些客户端会报错。
九、续期与自动化
Let's Encrypt 证书 90 天过期,需要自动续期。
检查续期任务:
sudo systemctl status certbot.timer
模拟续期(不真正替换证书):
sudo certbot renew --dry-run
看到类似输出说明没问题:
Congratulations, all simulated renewals succeeded
续期成功后,Nginx 通常需要重新加载,Certbot 的 Nginx 插件会自动处理。
十、常见排查方法
10.1 curl 检查 HTTP 跳转和 HTTPS
curl -I http://kb.example.com
curl -I https://kb.example.com
正常结果:
http -> 301 Moved Permanently,Location: https://kb.example.com/
https -> 200 OK
10.2 检查证书域名是否匹配
openssl s_client -connect kb.example.com:443 -servername kb.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -ext subjectAltName
确认 SAN 中包含 DNS:kb.example.com。
10.3 浏览器显示「Not secure」的常见原因
| 原因 | 说明 |
|---|---|
| 访问的是 HTTP | 地址栏没有 https:// |
| 混合内容 | HTTPS 页面里加载了 HTTP 资源 |
| 浏览器缓存了旧状态 | 之前访问过 HTTP,状态没有刷新 |
| 证书不匹配 | 域名不在 SAN 中 |
| 证书过期或链不完整 | 浏览器无法验证信任链 |
排查顺序建议:先用 curl 确认服务器端正常,再看浏览器。
十一、相关概念速查
| 术语 | 含义 |
|---|---|
| TLS | 传输层安全协议,HTTPS 的加密基础 |
| SSL | TLS 的旧称,现在仍常被混用 |
| CA | 证书颁发机构 |
| 证书链 | 服务器证书 → 中间证书 → 根证书 |
| SAN | 证书中的备用域名列表 |
| DV | 域名验证证书 |
| ACME | 自动申请证书的协议 |
| HTTP-01 / DNS-01 | 两种域名验证方式 |
| HSTS | 告诉浏览器「以后只用 HTTPS 访问这个站点」 |
| 私钥 | 只能留在服务器上,不能泄露 |
小结
证书是域名的身份证明。证书只能证明它列出的域名(SAN),不能自动覆盖新的子域名。给
kb子域名用 Let's Encrypt + Certbot,就是为它单独办一张「身份证」,免费、可自动续期。
速查
# 查看线上证书:颁发者、有效期、SAN
openssl s_client -connect kb.example.com:443 -servername kb.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
# 为子域名单独签发证书(自动修改 Nginx,并可选配置 HTTP → HTTPS 跳转)
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d kb.example.com
# 验证 HTTP 跳转与 HTTPS 状态
curl -I http://kb.example.com
curl -I https://kb.example.com
# 查看续期定时器 / 模拟续期
sudo systemctl status certbot.timer
sudo certbot renew --dry-run
# 修改 Nginx 配置后检查并重载
sudo nginx -t
sudo systemctl reload nginx
| 场景 | 结论 |
|---|---|
| 新子域名证书不匹配 | 子域名不在原证书 SAN 中,需单独签发或改用通配符证书 |
申请通配符 *.example.com | 必须用 DNS-01 验证 |
| 证书 90 天到期 | 用 certbot.timer + certbot renew 自动续期 |
| 浏览器仍提示不安全 | 先 curl -I 看跳转,再 openssl 看 SAN 与证书链 |
相关
- 生产部署记录:Nginx、systemd、Certbot 上线的完整步骤
- SSE 流式响应:HTTPS / Nginx 下流式回答的代理配置与排查
- 本地构建 + 同步部署到服务器:本站静态站点的发布方式
- 技术笔记总览:全部技术栈入口