腾讯云 DNS 自动更新 SSL 证书的思路
这套方案的核心不是去腾讯云控制台手动下载证书,而是把证书签发交给 ACME 客户端,把域名验证交给腾讯云 DNS API。这样证书到期前可以自动续签,续签成功后再自动把新证书安装到 nginx 使用的目录,并热加载 nginx。
适合的场景:
- 域名 DNS 托管在腾讯云 DNSPod。
- 网站跑在 nginx 后面。
- 需要自动续签 Let’s Encrypt、ZeroSSL 等 ACME 证书。
- 不想每 3 个月手动上传证书。
不适合的场景:
- 服务器完全不能访问外网。
- 域名不在腾讯云 DNSPod。
- 不方便在服务器保存一个权限受限的 DNS API 密钥。
整体流程
- 在腾讯云访问管理里创建一个专门用于 DNS 验证的 API 密钥。
- 服务器上安装
acme.sh。 - 把
Tencent_SecretId和Tencent_SecretKey放到环境变量或单独的密钥文件里。 acme.sh通过腾讯云 DNS API 临时添加_acme-challenge.example.comTXT 记录。- Let’s Encrypt 验证 TXT 记录后签发证书。
- 脚本把证书安装到 nginx 证书目录。
- nginx 测试配置成功后热加载。
- 后续由
acme.sh自带的 cron 定时续签,续签成功后自动执行 reload 命令。
这里最重要的是:密钥不要写进脚本正文,也不要提交到 Git。脚本只读取环境变量或 /etc/tencent-acme.env。
密钥文件
建议在服务器上创建:
sudo nano /etc/tencent-acme.env
内容类似这样:
Tencent_SecretId="AKIDxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Tencent_SecretKey="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
ACME_EMAIL="admin@example.com"
PRIMARY_DOMAIN="example.com"
DOMAINS="example.com www.example.com"
CERT_DIR="/etc/nginx/ssl/example.com"
NGINX_RELOAD_CMD="nginx -t && nginx -s reload"
然后收紧权限:
sudo chmod 600 /etc/tencent-acme.env
如果要申请泛域名证书,可以改成:
DOMAINS="example.com *.example.com"
nginx 配置
nginx 里引用脚本安装出来的证书:
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/nginx/ssl/example.com/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/example.com/example.com.key;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
自动更新脚本
模板脚本放在同目录:
软件/tencent-ssl-auto-renew-template.sh
第一次执行:
chmod +x tencent-ssl-auto-renew-template.sh
sudo ENV_FILE=/etc/tencent-acme.env ./tencent-ssl-auto-renew-template.sh
后续一般不用自己再写定时任务,因为 acme.sh 安装后会创建自己的 cron。它会定期检查证书,只有临近过期才续签;续签成功后会执行 --reloadcmd 里配置的 nginx reload 命令。
如果要手动强制重签:
sudo ENV_FILE=/etc/tencent-acme.env FORCE_RENEW=1 ./tencent-ssl-auto-renew-template.sh
Windows nginx 的处理
如果 nginx 跑在 Windows 上,思路不变,但更推荐用 WSL 跑 acme.sh:
- WSL 里签发证书。
- 把证书安装到一个 Windows nginx 能读取的目录,例如
/mnt/c/nginx/cert/example.com。 NGINX_RELOAD_CMD改成调用 Windows nginx 的 reload 命令。
例如:
CERT_DIR="/mnt/c/nginx/cert/example.com"
NGINX_RELOAD_CMD="/mnt/c/nginx/nginx.exe -p C:/nginx -s reload"
如果 nginx 实际路径是 C:\Users\Administrator\Desktop\nginx-1.18.0,可以按自己的目录改成对应的 /mnt/c/Users/Administrator/Desktop/nginx-1.18.0/...。
安全边界
这套方案真正敏感的是腾讯云 API 密钥,不是脚本本身。公开脚本时应该遵守几条规则:
- 脚本里只写变量名,不写真实
SecretId和SecretKey。 - 给这个密钥最小权限,只允许操作 DNS 解析,不要用主账号全权限密钥。
- 密钥文件放在服务器本地,权限设为
600。 - 不要把
/etc/tencent-acme.env、.env、account.conf提交到 Git。 - 如果密钥泄露,立刻在腾讯云控制台禁用并重新生成。
常见问题
为什么不用 HTTP 验证?
HTTP 验证要求公网能访问 /.well-known/acme-challenge/,并且泛域名证书不能用 HTTP 验证。DNS 验证更通用,也更适合 nginx、反代、多站点混合部署。
为什么用 acme.sh?
acme.sh 是纯 shell ACME 客户端,腾讯云官方文档和 acme.sh 官方 DNS 插件都支持 dns_tencent,只需要提供 Tencent_SecretId 和 Tencent_SecretKey。
证书更新后 nginx 会自动使用新证书吗?
会。关键是 --install-cert 里的 --reloadcmd。证书续签并安装成功后,acme.sh 会执行这条命令。建议写成:
nginx -t && nginx -s reload
这样 nginx 配置测试失败时不会强行 reload。
参考资料
- 腾讯云 DNSPod 文档:
acme.sh自动解析并申请证书。 - acme.sh 官方
dns_tencent插件:使用Tencent_SecretId和Tencent_SecretKey调用腾讯云 DNS API。