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/