我这个网站之前一直使用阿里云的免费 SSL 证书,每次申请后能管一年。最近证书快要到期,准备重新申请下一个年度的 SSL 证书,登录到阿里云后台发现这个功能有了些变化。免费证书名字改成了测试证书,一年的有效时长也变成了三个月,如果想要一年时长的证书,需要交费 68 元。网站本来就没收入,本着能省就省的原则,决定还是改用 Let’s Encrypt。
Let’s Encrypt 是一家国外免费的证书颁发机构,已经运营多年,稳定性令人放心。虽然证书申请后也只有三个月有效期,但支持通过程序自动化续期,体验上跟长期证书并无二致,就这点来看,阿里云还有得学。
证书申请
Let’s Encrypt 支持很多 ACME(自动证书管理环境)协议的客户端软件,官方目前推荐的是 Certbot,所以我也准备使用这个客户端。Certbot 基于 Python 语言,所以首先要准备好 Python 执行环境:
python3 -m venv ./venv
source venv/bin/activate
Linux 服务器一般都自带了 Python 执行环境,所以上面这步并不是必须的,只是我的个人软件安装洁癖,习惯了给不同的软件配置隔离的执行环境。
接下来开始用 pip
命令安装 Certbot:
pip install certbot certbot-nginx
我用的 Web 服务是 Nginx,所以还搭上了 certbot-nginx
扩展。安装好 Certbot 后,就可以开始通过命令给网站申请证书。申请适用于 Nginx 的 SSL 证书命令如下:
sudo certbot certonly --nginx
第一次执行需要完成几个交互式的选项,按提示操作即可。在操作的过程中,会根据 Nginx 中的站点配置自动列出可以申请的域名。
如果只是给特定的域名申请 SSL 证书,可以使用 -d
命令选项指定域名:
sudo certbot --nginx -d www.zzxworld.com
命令执行成功后会有如下所示的输出内容:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/www.zzxworld.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/www.zzxworld.com/privkey.pem
This certificate expires on 2024-12-22.
脚本会在域名的 Nginx 配置中自动插入证书配置,证书相关的配置示例如下:
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/v2.miparts.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/v2.miparts.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
if ($scheme != "https") {
return 301 https://$host$request_uri;
}
证书续期
证书续期同样是使用 certbot
命令,可以手动测试一下续期命令:
sudo certbot renew --dry-run
以上命令会根据当前服务器上已经申请的域名 SSL 证书模拟续期操作,一切无误会输出以下内容:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/www.zzxworld.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
去掉命令后的 --dry-run
参数就可以开始真正的续期操作,续期成功后,证书的有效期又能延期三个月,所以接下来只要记得每三个月登录到服务器上执行一次命令即可。
三个月操作一次虽然并没有多大负担,但能交给软件自动化执行的事情也没必要自己一直记着。结合 Linux 服务器上的 Crontab 计划任务,就能实现让证书自动无限续期:
0 0 * * 0 certbot renew --quiet --post-hook "systemctl restart nginx"
以上自动任务设置为每周执行一次续期命令,之所以按周是因为 Let’s Encrypt 的证书续期只有在过期前 30 天内才能生效,按天执行频率过高,按月的话容错率低,综合来看,按周是比较合理的。
实际使用中发现,续期命令的确存在执行失败的问题,所以稳妥起见,还是要定期人工检查一下站点证书的到期时间。比如上面的命令是每周日执行一次续签,我就在手机上设定了一个每周一检查站点证书的提醒事项,以确保自动续签失败时能及时人工处理。