Jw
首页
技术
英语
首页
技术
英语
  • 本站部署

    • 本地构建 + 同步到服务器
  • 知微(知识库 Agent)

    • 生产部署记录
    • HTTPS 证书基础
    • SSE 流式响应

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 列表里?

答案是否定的,于是报证书不匹配错误。

所以解决方法只有三种:

  1. 为 kb.example.com 单独申请一张证书(最简单,本项目采用)
  2. 购买/申请通配符证书 *.example.com,覆盖所有子域名
  3. 把应用放到已有域名的路径下,例如 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 通常会:

  1. 完成 HTTP-01 域名验证
  2. 把证书保存到 /etc/letsencrypt/live/kb.example.com/
  3. 修改 Nginx 配置,添加 listen 443 ssl
  4. 可选:把 HTTP 自动跳转到 HTTPS
  5. 配置定时任务自动续期

证书文件:

/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 的加密基础
SSLTLS 的旧称,现在仍常被混用
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 下流式回答的代理配置与排查
  • 本地构建 + 同步部署到服务器:本站静态站点的发布方式
  • 技术笔记总览:全部技术栈入口
最近更新: 2026/10/25 10:17
Contributors: liujw
Prev
生产部署记录
Next
SSE 流式响应