腾讯云 DNS 自动更新 SSL 证书的思路

这套方案的核心不是去腾讯云控制台手动下载证书,而是把证书签发交给 ACME 客户端,把域名验证交给腾讯云 DNS API。这样证书到期前可以自动续签,续签成功后再自动把新证书安装到 nginx 使用的目录,并热加载 nginx。

适合的场景:

  • 域名 DNS 托管在腾讯云 DNSPod。
  • 网站跑在 nginx 后面。
  • 需要自动续签 Let’s Encrypt、ZeroSSL 等 ACME 证书。
  • 不想每 3 个月手动上传证书。

不适合的场景:

  • 服务器完全不能访问外网。
  • 域名不在腾讯云 DNSPod。
  • 不方便在服务器保存一个权限受限的 DNS API 密钥。

整体流程

  1. 在腾讯云访问管理里创建一个专门用于 DNS 验证的 API 密钥。
  2. 服务器上安装 acme.sh
  3. Tencent_SecretIdTencent_SecretKey 放到环境变量或单独的密钥文件里。
  4. acme.sh 通过腾讯云 DNS API 临时添加 _acme-challenge.example.com TXT 记录。
  5. Let’s Encrypt 验证 TXT 记录后签发证书。
  6. 脚本把证书安装到 nginx 证书目录。
  7. nginx 测试配置成功后热加载。
  8. 后续由 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

  1. WSL 里签发证书。
  2. 把证书安装到一个 Windows nginx 能读取的目录,例如 /mnt/c/nginx/cert/example.com
  3. 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 密钥,不是脚本本身。公开脚本时应该遵守几条规则:

  • 脚本里只写变量名,不写真实 SecretIdSecretKey
  • 给这个密钥最小权限,只允许操作 DNS 解析,不要用主账号全权限密钥。
  • 密钥文件放在服务器本地,权限设为 600
  • 不要把 /etc/tencent-acme.env.envaccount.conf 提交到 Git。
  • 如果密钥泄露,立刻在腾讯云控制台禁用并重新生成。

常见问题

为什么不用 HTTP 验证?

HTTP 验证要求公网能访问 /.well-known/acme-challenge/,并且泛域名证书不能用 HTTP 验证。DNS 验证更通用,也更适合 nginx、反代、多站点混合部署。

为什么用 acme.sh?

acme.sh 是纯 shell ACME 客户端,腾讯云官方文档和 acme.sh 官方 DNS 插件都支持 dns_tencent,只需要提供 Tencent_SecretIdTencent_SecretKey

证书更新后 nginx 会自动使用新证书吗?

会。关键是 --install-cert 里的 --reloadcmd。证书续签并安装成功后,acme.sh 会执行这条命令。建议写成:

nginx -t && nginx -s reload

这样 nginx 配置测试失败时不会强行 reload。

参考资料

  • 腾讯云 DNSPod 文档:acme.sh 自动解析并申请证书。
  • acme.sh 官方 dns_tencent 插件:使用 Tencent_SecretIdTencent_SecretKey 调用腾讯云 DNS API。