3.3 SSL 证书:免费 DV 证书申请与部署
域名解析通的当天下午,合伙人在微信里打开了站点,丢来一句:浏览器提示不安全,客户看到还以为我们被盗号了。我一看,http 明文裸奔,地址栏一个灰色感叹号。当晚就把证书提上日程——不是因为它难,而是它不做,前面所有工作在用户眼里都不专业。另外上了 HTTPS 才能用上 HTTP/2,对首屏速度也有帮助,这在 1.2 选型对比 里算过一笔账。
本节讲我们用免费 DV 证书搞定 HTTPS 的全过程:选证书、申请、DNS 验证、部署到 CDN、开强制跳转,外加三个差点让整站不可用的坑。腾讯云 SSL 证书服务提供免费 DV 证书,个人项目与小型创业站完全够用。
3.3.1 先选对证书类型
先给一张对照表,省得在控制台里挑花眼:
| 类型 | 验证方式 | 价格 | 签发速度 | 我们的项目 |
|---|---|---|---|---|
| DV 免费版 | 自动 DNS 验证 | 免费 | 10 分钟内 | 正在用 |
| OV 付费版 | 人工审核组织信息 | 数百元每年 | 数天 | 用不上 |
| EV 付费版 | 严格人工审核 | 更贵 | 更久 | 用不上 |
DV 只验证域名所有权,不验证公司主体,但浏览器一样显示小锁,差别只是证书详情里没有公司名。对静态创业页来说,免费 DV 是唯一合理的选择。要接受的唯一代价是有效期——免费证书一次签发一年,到期必须续,这就是 3.3.4 坑二的内容。
顺带一个真实小插曲:最初我也动过自签证书的念头,本地起一个 OpenSSL 签一张,十分钟搞定。合伙人文档里查到自签证书在浏览器里照样是红色感叹号,还要手动教每个客户点继续访问,遂作罢。免费 DV 的成本是每年点几下控制台,收益是所有用户无感通过,这笔账不用算。
顺带说说为什么必须上 HTTPS,给团队算账时用得着。三条理由:一是浏览器信任,地址栏没有小锁的站点在客户眼里约等于路边摊;二是性能,HTTPS 才能协商 HTTP/2,多路复用对首屏加载有实打实的提升;三是生态强制,微信小程序的业务域名、部分平台的分享卡片预览,通通要求 https 接口,明文站点连被集成的资格都没有。成本是零,收益是三重,没有理由不做。
3.3.2 申请与 DNS 验证
控制台路径是 SSL 证书、我的证书、申请免费证书。表单只有两项要填:域名(填 www.example.com,根域需要的话再申请一张,或干脆申请泛域名证书)和联系邮箱。这里有个小技巧:证书申请的域名和 3.2 节解析的域名必须严格一致,少一个或多一个 www 都不行,浏览器校验证书时按精确匹配来。提交后进入验证:平台给一条 CNAME 记录,格式类似 _dnsauth.www 指向一串 sslverify 地址。
巧的是这条记录加在 3.2 解析 同一个解析控制台里。由于 DNSPod 与证书服务同属腾讯云生态,记录可以一键自动添加,我们手动加过一次、自动加过一次,速度没区别,自动更省事。加完回证书页点验证,几分钟内状态变绿。
一个决策点:单域名证书还是泛域名证书(星号开头的泛解析)。泛域名一张证书护住所有子域,以后加 blog、api 子域不用重新申请。我们的子域规划只有 www 和根域,所以两张单域名证书比一张泛证书更直接,也省得到期换证波及全部子域。如果产品规划里子域明确会越加越多,泛域名是更好的选择。两种方案的对比如下:
| 方案 | 覆盖范围 | 到期影响 | 我们的选择 |
|---|---|---|---|
| 单域名证书 | 一个精确域名 | 换证只影响该域 | 两张:www 与根域 |
| 泛域名证书 | 所有一级子域 | 一张过期全部子域遭殃 | 子域多时改用 |
新手最容易忽略的细节是:泛域名证书并不覆盖根域本身,星号只匹配子域层级。也就是说,买了泛证书还得再为根域单独配一张,否则 example.com 依然是明文。我们把这事写进了上线 checklist,每次新增子域前先回头看证书覆盖范围。两个选择的对照:
| 维度 | 单域名证书 | 泛域名证书 |
|---|---|---|
| 覆盖范围 | 一个精确域名 | 一级下所有子域 |
| 到期影响 | 只影响一个子域 | 全部子域一起换 |
| 申请成本 | 每个子域各一张 | 一张搞定 |
| 管理难度 | 多了容易记岔 | 省心 |
顺带提一句本地开发:https 的线上行为在本地测不了,可以用 mkcert 本地自签证书,浏览器会信任,行为和线上一致。我们做混合内容检查就是先在本地 https 环境跑通的。
3.3.3 部署:证书挂到 CDN 上
证书签发后不是自动生效的,要手动部署。部署位置取决于流量走到哪:我们的链路是 CDN 加速域名承载流量,所以选部署到 CDN:SSL 控制台里选部署、勾选 3.2 节接入的那个加速域名,一两分钟完成。如果你的站没接 CDN、直接走托管平台默认域名,就部署到托管平台;这两种位置的差别值得记住:
| 部署位置 | 适用场景 | 注意事项 |
|---|---|---|
| CDN 加速域名 | 自定义域名走 CDN | 部署完刷一次缓存 |
| 托管平台默认域 | apa 域名直接用 | 一般送证书平台自动管理 |
| 轻量服务器 | 自建 Nginx 部署 | 证书要自己下发到服务器并配 443 |
部署完两件事必须配。一是强制 HTTPS 跳转,在 CDN 控制台 HTTPS 配置里打开 301 重定向,所有 http 请求自动跳 https,源站再支持明文都无所谓。二是回源协议同步改成 HTTPS,避免端到端链路里还有明文段落。
验证用无痕窗口(避开本地缓存)加命令行:
curl -I http://www.example.com
curl -I https://www.example.com
第一行返回 301 且 Location 指向 https,第二行返回 200,链路就是通的。典型输出长这样:
HTTP/1.1 301 Moved Permanently
Location: https://www.example.com/
HTTP/1.1 200 OK
strict-transport-security: max-age=31536000
浏览器里确认小锁为绿色锁定状态,证书详情能看到签发机构即可。想提前知道证书哪天到期,不用等告警,命令行直接查:
openssl s_client -connect www.example.com:443 -servername www.example.com </dev/null 2>/dev/null | openssl x509 -noout -dates
输出里的 notBefore 与 notAfter 就是起止日期,我们把它做成了每周轮询的脚本,到期前 30 天在企业微信里推送提醒。
3.3.4 三个坑
坑一:混合内容。HTTPS 跑起来,首页小锁有了,但产品详情页的小锁消失——原因是正文里两张营销图还写着 http 绝对地址。浏览器把明文图片判为不安全资源,小锁就消失。更隐蔽的是第三方统计脚本,当时我们也漏了一个,直到控制台报 mixed content 才发现。解法:全站资源统一协议,img src 一律相对路径或 https,第三方脚本实在改不了协议就换服务商。我们在 CI 里加了一条 grep 检查,产物里出现 http:// 开头的资源引用直接报错——能在构建期拦住的,绝不留到线上,这个思路在 3.4 构建排查 里展开成了完整预检清单。
坑二:证书过期。免费证书到期那周,监控突然告警整站证书失效,打开果然是浏览器拦截页。续期本身免费,但要重新走一遍申请部署流程,期间站点处于半残状态。之后设了两道保险:日历提醒提前 30 天,加云监控的证书到期告警,5.2 监控告警 那节会展开告警怎么配。另外证书的过期时间可以主动查,部署脚本里加一行自检:
openssl s_client -connect www.example.com:443 </dev/null 2>/dev/null \
| openssl x509 -noout -dates
输出里的 notAfter 就是到期日。我们把这条命令封进 precheck,距离到期不足 21 天就在部署日志里打警告,谁部署谁看见,想忘都忘不掉。
坑三:部署后没刷新缓存。证书换了,CDN 节点上的旧会话还在,部分用户看到旧证书报错。部署完成后顺手触发一次 CDN 缓存刷新,这个动作在第四篇 4.1 CDN 接入 里被写进了部署脚本,而不是靠手动记。
小结
HTTPS 的闭环是:申请 DV、DNS 验证、部署到 CDN、开 301 强制跳转、混合内容体检、到期告警。每一步都不难,难的是把它们串成不依赖个人记忆的流程。证书挂好,第三篇只剩最后一道关卡:3.4 常见构建失败与排查,把上线前那些猝不及防的红色报错整理成清单。
延伸阅读
- Node.js 网站托管实战:本书目录,第三篇第四节整理构建失败清单。
- 腾讯云实践案例集:更多云上 HTTPS 与缓存配置的实战记录。
- 轻量应用服务器建站实战:服务器路线的证书配置方式对照。
