SSL 证书一键申请
很多站长在申请免费 SSL 证书时绕了远路:要么去平台后台手动下载、上传证书文件,要么纠结该买哪种付费证书。其实用 Certbot + Let's Encrypt,一条命令就能申请并自动续期,Nginx 和 Apache 都支持自动配置。下面是完整的操作流程。
先解释一下原理,方便你理解后面每条命令在干什么。Let's Encrypt 是一个免费、自动化的证书颁发机构,它基于 ACME 协议工作:Certbot 作为客户端,向 Let's Encrypt 证明"你确实控制这个域名",验证通过后证书就签发下来。整个流程不依赖人工审核,所以可以反复申请和自动续期。你唯一要付出的代价是证书只有 90 天有效期——这也是很多人一开始觉得"麻烦"的地方,但其实这正是它安全的来源:证书短期化之后,即使私钥泄露,影响范围也被限制在三个月内。Certbot 安装时会自动添加 systemd 定时器,每 60 天检查一次并自动续期,全程无需人工干预。
安装 Certbot
# 安装 Certbot(Nginx 模式)
apt install certbot python3-certbot-nginx -y
# 申请证书(自动修改 Nginx 配置)
certbot --nginx -d example.com -d www.example.com
# 续期测试(不真正续期,只验证)
certbot renew --dry-run
# 查看已签发证书
certbot certificates
certbot --nginx 模式会做三件事:自动检测 Nginx 站点配置、临时改配置完成 HTTP 验证、把证书路径写进 server 块。如果担心它改坏配置,可以先 cp 备份 /etc/nginx/sites-available/ 下的配置文件再执行。不加 --nginx 参数、只跑 certbot certonly 也能申请,但证书路径和 Nginx 配置就得自己手动填,容易出错。
泛域名证书怎么申请
一个二级域名对应一张证书,子域名很多时逐个申请很麻烦。泛域名证书用 *.example.com 覆盖所有子域名,但需要 DNS 验证而不是 HTTP 验证:
# 手动 DNS 验证
certbot certonly --manual --preferred-challenges dns \
-d *.example.com -d example.com
# 或使用 DNS 插件自动验证(以 Cloudflare 为例)
# 需先配置 ~/.cloudflare/credentials
certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials ~/.cloudflare/credentials \
-d *.example.com -d example.com
为什么泛域名必须走 DNS 验证?因为 HTTP 验证要求"每个子域名都能通过 80 端口回连到这台服务器",而 *.example.com 指向无数个子域,不可能逐一验证。DNS 验证则是让 Let's Encrypt 检查一个特殊 TXT 记录 _acme-challenge,只要你能在 DNS 控制台添加这条记录,就等于证明了域名控制权。手动模式要等 TXT 记录生效(通常几分钟),用 DNS 插件则全自动。如果你的域名服务商没有对应插件,又不想手动,也可以用 acme.sh 这类工具,它支持的 DNS 服务商更多。
Nginx 里的 SSL 配置
证书申请成功后,Nginx 站点配置大概长这样:
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 现代 TLS 配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
}
# HTTP 跳转 HTTPS
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
这里有两个容易被忽略的细节。第一,证书文件路径要写 /etc/letsencrypt/live/<域名>/ 而不是 archive 目录,因为 live 目录下的文件是软链接,续期后会自动指向新证书,站点无需重启;如果你手动把证书文件复制到了别的路径,续期后就会失效。第二,ssl_protocols 只保留 TLSv1.2 和 TLSv1.3 即可,TLSv1.0/1.1 早在 2020 年就被主流浏览器移除了支持,留着反而会成为扫描器的目标。如果追求更高的安全评级,可以再加 HSTS 头,让浏览器只走 HTTPS 访问。
自动续期
Let's Encrypt 证书有效期只有 90 天,所以自动续期不是可选项。Certbot 安装时会自动添加 systemd 定时器,每天检查一次:
# 查看续期定时器
systemctl list-timers | grep certbot
# 手动触发续期检查
certbot renew --force-renewal
# 查看续期日志
grep -i "renew\|success" /var/log/letsencrypt/letsencrypt.log
判断续期是否正常,最稳妥的方法是隔一段时间跑一次 certbot renew --dry-run,它能模拟完整续期流程而不真正续期。如果服务器时区或时间不准,或者 DNS 解析偶尔抽风,续期就会失败,所以建议把续期失败也纳入告警。这里要提醒一点:HTTP 验证续期同样依赖 80 端口,如果你的服务器在续期时段刚好重启了 Nginx 或者防火墙挡住了 80 端口,续期就会失败,这也是前面留 80 端口开放的另一个原因。
常见问题对照
| 报错信息 | 解决办法 |
|---|---|
Could not bind to port 80 |
先停掉占用 80 端口的服务,如 systemctl stop nginx |
Too many certificates |
Let's Encrypt 每个域名每周限 50 张,避免反复重签 |
DNS problem: NXDOMAIN |
确认域名解析已指向这台服务器 |
| 续期失败 | 检查 80 端口可达、域名解析是否正常 |
场景与建议
如果站点使用了 CDN 代理,注意在 CDN 后台把 SSL 模式设置为 Full (Strict),否则会出现证书链不完整或循环跳转。举例来说:你的源站有 Let's Encrypt 证书,CDN 用自己的证书提供 HTTPS,两者之间的链路如果设置成 Flexible,CDN 回源时会走 HTTP,浏览器看到的是"地址栏有锁、但内容其实是明文传输的"。Full (Strict) 模式要求源站证书真实有效,这样整条链路才都是加密的。整体上,Let's Encrypt 免费证书对绝大多数个人站和中小站点完全够用;如果你的业务对合规要求极高、需要一年有效期的 OV/EV 证书,才需要考虑付费方案,具体区别可以看SSL 证书类型指南。
详细流程可参考Let's Encrypt SSL 配置指南和Certbot 自动化配置,上线后记得把 HTTP 重定向到 HTTPS,并配合证书到期监控,避免证书过期导致站点无法访问。
参考
参考:Certbot 官方文档 https://certbot.eff.org/
参考:Let's Encrypt 文档 https://letsencrypt.org/docs/
参考:SSL Labs 在线检测 https://www.ssllabs.com/ssltest/
参考:Mozilla SSL 配置生成器 https://ssl-config.mozilla.org/