自动部署 HTTPS 证书
需求
之前使用腾讯云的证书,只有 90 天的有效期,每次到期了就要手动部署,下载 .crt
和 .pri
文件(或者是 .key
,吧,记不清了),然后手动移动到对应的文件夹。一个域名就要花好几分钟,效率很低。
因此问了问 AI,有什么更好的方案。最终决定采用 Let’s Encrypt 和 Certbot 结合的自动化方案。
哪个证书
这里需要澄清一个问题。Cloudflare 有一个 Edge Certficate 的方案,可以自动化地续期证书,这个证书是浏览器访问域名时用到的证书。
然而在 Cloudflare 的服务器和源服务器之间,仍然需要自动化处理证书。本文要解决的是后者。
1 | 用户 -- Edge Certificate --> CF 代理服务器 -- 本文要解决的证书 --> 源服务器 |
环境配置
安装 snapd
1 | sudo apt update |
安装 Certbot
1 | sudo snap install core # 确保 snap 运行环境是最新的 |
创建软链接
1 | sudo ln -s /snap/bin/certbot /usr/bin/certbot |
一番操作下来,Azure 的网络是最好的,aws 还是慢。但 Azure 好贵啊,额度用完后估计要迁移到 aws 了,又是一番折腾。
申请证书
1 | sudo certbot --nginx -d example.com -d www.example.com |
理想很丰满,实际上会报错:
1 | Certbot failed to authenticate some domains (authenticator: nginx). The Certificate Authority reported these problems: |
原因是因为我的服务器走了 Cloudflare 的代理,导致域名解析到的不是源服务器,而是 Cloudflare 的代理服务器。
难不成每次都要关闭代理?肯定有更好的方案。
使用 Cloudflare API 进行 DNS 方式验证
获取 Cloudflare API 令牌
在令牌管理页面,新建一个 API 令牌。
使用“编辑 DNS”权限(只修改 DNS 记录,不影响其他功能)
这里需要注意的就是,限制一下允许调用这个 API 的 IP 范围,设置为自己的服务器 IP 即可。不设置的话,不允许前进。
安装 Cloudflare DNS 插件
1 | sudo apt install python3-certbot-dns-cloudflare |
配置 API 令牌
1 | mkdir -p ~/.secrets/certbot |
添加:
1 | dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN |
设置权限:
1 | chmod 600 ~/.secrets/certbot/cloudflare.ini |
申请证书
1 | sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini -d example.com -d www.example.com |
这里注意,有可能失败,报错:
1 | Certbot failed to authenticate some domains (authenticator: dns-cloudflare). The Certificate Authority reported these problems: |
Hint 中提示的很清晰了,可以尝试增大等待时间,对我来说,25 秒可行。
最后返回的成功信息是:
1 | Successfully received certificate. |
配置 Nginx
接下来需要在 nginx 中配置使用的证书:
1 | server { |
因为这里可能要多次复制粘贴,所以分享几个 vim 的使用技巧:
- 复制两行:
2yy
; - 粘贴:
p
; - 打开新文件:
:tabe
; - 切换到下一个文件:
:tabn
; - 切换到上一个文件:
:tabp
。
然后测试一下配置是否正确:
1 | sudo nginx -t |
最后重启 nginx
1 | sudo systemctl restart nginx |
设置自动续期
Certbot 会自动续期:
1 | Certbot has set up a scheduled task to automatically renew this certificate in the background. |
不过它并不会自动重启 nginx
,所以导致 nginx
可能使用的仍然是旧证书。
为此,设置一个钩子:
1 | sudo vim /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh |
写入:
1 |
|
然后赋予执行权限:
1 | sudo chmod +x /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh |
終わり。