HTTPS 与证书:浏览器那把小锁背后
2026-05-17
HTTPS 就是在 HTTP 之下加了一层 TLS 加密,目的有三个:内容不被窃听、不被篡改、确认对方就是你要访问的网站。
为什么一定要上 HTTPS
早期的 HTTP 是明文传输的,同一个网络里的人理论上能看到你提交的表单,中间设备甚至能往页面里插内容。HTTPS 解决的就是这件事。现在主流浏览器会把没有 HTTPS 的页面标为“不安全”,很多新的浏览器功能也只在 HTTPS 下可用。对个人博客来说,部署 HTTPS 的成本已经很低,没有理由不做。
TLS 握手的大致过程
- 客户端发起连接,告诉服务器自己支持的 TLS 版本和加密套件。
- 服务器选定参数,并把自己的证书发给客户端。
- 客户端校验证书:是否由受信任的 CA 签发、域名是否匹配、是否在有效期内。
- 双方通过密钥交换协商出一把只有彼此知道的会话密钥。
- 之后的数据都用这把会话密钥加密传输。
可以这样理解:证书用来证明“你是谁”,密钥交换用来解决“怎么安全地约定密码”,对称加密用来负责“高效地传数据”。三者各司其职。
证书怎么来的
网站向证书颁发机构(CA)申请证书,CA 验证你确实控制这个域名后签发。浏览器内置了受信任的 CA 列表,用它来校验网站出示的证书。
证书里主要包含:域名(现在以 SAN 字段为准)、公钥、有效期、签发者和签名。实际部署中,服务器通常还要提供“中间证书”,组成一条从站点证书到受信任根证书的证书链,缺了中间证书,一些客户端就会报错。
免费且自动:Let's Encrypt
Let's Encrypt 提供免费证书,有效期较短,需要自动续期。Caddy、certbot 等工具可以自动申请和续期。以 Caddy 为例,只要域名已解析到服务器,且 80/443 端口可访问,在配置里写上站点域名就会自动启用 HTTPS。
用 Caddy 的最小配置
在 Debian 或 Ubuntu 上,Caddy 的配置文件通常是 /etc/caddy/Caddyfile。一个托管静态博客的最小例子:
example.com, www.example.com {
root * /var/www/blog
file_server
encode gzip
}
修改后先检查再重载:
sudo caddy validate --config /etc/caddy/Caddyfile sudo systemctl reload caddy sudo journalctl -u caddy --no-pager -n 50
最后一条可以查看最近日志,申请证书的成功或失败原因都在这里。更多写法见 Caddy 一文。
用 certbot 的做法
如果你用的是 Nginx,可以用 certbot。在 Debian 或 Ubuntu 上:
sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d example.com -d www.example.com sudo certbot renew --dry-run
第三条是模拟续期,用来确认自动续期流程没有问题,建议安装后一定执行一次。系统通常会通过定时任务或 systemd 定时器自动执行续期,可以用 systemctl list-timers 查看是否存在 certbot 相关的计时器。
申请证书前的准备清单
- 域名已经解析到这台服务器,见 DNS 是什么。
- 80 和 443 端口在系统防火墙和云厂商安全组中都已放行,见 防火墙。
- 没有别的程序占用 80/443,可以用
sudo ss -tlnp | grep -E ':80|:443'检查。 - 服务器放在中国大陆时,域名需要先通过接入服务商办理 ICP 备案,才能对外提供网站服务。
常见问题
- 申请失败:多半是域名没解析到本机,或 80/443 被防火墙拦截。
- 混合内容:HTTPS 页面里引用 http 资源会被浏览器拦截,需要改成 https。
- 证书过期:检查自动续期任务是否正常运行。
进一步排查
怀疑证书有问题时,我会先用下面的命令看证书的主题、签发者和有效期:
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates
其中 -servername 很重要,它告诉服务器要访问哪个域名,一台服务器托管多个站点时缺了它会拿到默认证书。也可以用 curl -vI https://example.com 查看握手和响应头。
浏览器里常见的报错也各有含义:证书域名不匹配,说明证书里没有你访问的这个域名;证书已过期,说明续期失败;不受信任的颁发者,可能是缺少中间证书,或使用了自签名证书。自签名证书只适合内部测试,不要用在对外的站点上。
几个容易踩的坑
- 时间不对:服务器或客户端时间严重偏差,会让证书看起来“尚未生效”或“已过期”,先确认时间同步。
- 频繁重复申请:证书颁发机构对申请次数有频率限制,调试时反复申请可能被暂时拒绝,调试阶段可以使用其提供的测试环境,具体见官方文档。
- CDN 和反向代理:前面如果还有一层代理,需要弄清楚 HTTPS 是在哪一层终止的,以及代理到源站这一段是否也加密。
- HTTP 跳转:证书部署好之后,把 HTTP 请求跳转到 HTTPS,Caddy 默认就会做这件事,Nginx 需要自己配置 301 跳转。
- 私钥泄露:私钥文件不要上传到公开仓库,也不要发给别人,一旦泄露应立即重新签发证书。
HSTS 是什么
HSTS 是一个响应头,告诉浏览器在一段时间内只能用 HTTPS 访问本站,防止被降级到 HTTP。启用前要确认 HTTPS 稳定可用,因为一旦设置了较长的有效期,证书出问题时用户将无法通过点击“继续访问”绕过,请谨慎使用较长的时间。
和 SSH 的关系
HTTPS 保护的是访问网站的流量,管理服务器用的 SSH 是另一套加密通道,二者互不替代。服务器的远程登录安全见 SSH 安全加固,机器的基础配置见 VPS 入门。
TLS 版本与加密套件的选择
现代的 TLS 版本有 1.2 和 1.3,更老的 SSL 以及 TLS 1.0、1.1 已被淘汰。Caddy 默认配置已经比较合理,通常不需要改。如果你使用 Nginx,可以参考 Mozilla 提供的 SSL 配置生成器,选择与自己客户端范围匹配的方案,不要凭印象随手拼凑加密套件。除非有明确的兼容性需求,否则不要为了支持极老的设备而降低整体安全水平。
通配符证书与 DNS 验证
普通的 HTTP 验证要求域名解析到服务器并能访问 80 端口。如果你想要一张覆盖 *.example.com 的通配符证书,通常需要使用 DNS 验证:在域名下添加指定的 TXT 记录来证明所有权。这种方式不要求开放 80 端口,也适合内网服务,但需要 DNS 服务商提供 API 或手动添加记录,自动续期时还要配合对应的插件,具体用法请看所用工具的文档,这里不展开。
上线后的检查清单
- 用浏览器访问 https 地址,点击小锁确认证书信息与域名一致。
- 访问 http 地址,确认会自动跳转到 https。
- 打开浏览器开发者工具的控制台,检查是否有混合内容警告。
- 确认续期机制存在:Caddy 看日志,certbot 看
systemctl list-timers。 - 在日历里记下证书有效期,作为自动续期失效时的最后保险。
总结
HTTPS 通过证书确认身份,通过 TLS 加密传输。免费证书加上自动续期,让个人站点部署它变得很简单。真正容易出问题的地方往往不是加密本身,而是域名解析、端口放行、证书链、续期和混合内容。遇到问题时,沿着“解析是否正确、端口是否能通、日志怎么说、证书长什么样”这条线逐步排查,基本都能找到原因。