Windows 平台 SSL 证书:腾讯云自动更新
这份说明记录的是 Windows Server + nginx 的 SSL 证书自动更新思路。它不是用 acme.sh 重新签发证书,也不是通过 DNS TXT 记录做 ACME 验证;当前更贴近的实现是:
- 证书仍然在腾讯云 SSL 证书控制台签发、续期。
- Windows 定时任务每天运行一次 PowerShell 脚本。
- 脚本调用腾讯云 SSL API 下载已签发证书的 ZIP 包。
- 解压 ZIP,取出
Nginx目录里的证书文件。 - 备份 nginx 当前证书,再复制新证书到 nginx 的
conf\key目录。 - 执行
nginx.exe -t检查配置,成功后nginx.exe -s reload热加载。
这样做的好处是:不需要手动登录腾讯云下载证书,也不需要每次手动替换 nginx 证书文件。证书真正续期完成后,服务器会在下一次定时任务里自动把新证书同步下来。
当前服务器检查结果
这次检查远端时,能看到服务器上有一个计划任务:
AutoUpdateTencentSSL
计划任务是每天运行一次,服务器证书目录里也能看到 2026-07-03 下载并替换过的证书文件,说明之前确实走过“下载腾讯云证书包并复制到 nginx”的流程。
不过也发现一个需要注意的问题:当前计划任务参数看起来被 Windows 命令行引号污染过,类似 /RU SYSTEM /RL HIGHEST 被拼进了 PowerShell 参数里,并且任务引用的 C:\ssl-auto\Update-TencentSsl.ps1 当前没有找到。后续如果要真正恢复自动更新,需要重新放回脚本,并重新注册一次计划任务。
目录建议
建议把自动更新相关文件统一放在:
C:\ssl-auto
推荐结构:
C:\ssl-auto
Update-TencentSsl.ps1
tencent-ssl.env.ps1
logs\
work\
zips\
extract\
backup\
Update-TencentSsl.ps1 是自动更新脚本,tencent-ssl.env.ps1 是密钥和域名配置。密钥文件不要提交到 Git,也不要公开。
密钥配置
创建:
C:\ssl-auto\tencent-ssl.env.ps1
内容示例:
$TencentSecretId = "AKIDxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$TencentSecretKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$NginxRoot = "C:\nginx-1.18.0"
$CertTargetDir = Join-Path $NginxRoot "conf\key"
$Certificates = @(
@{
Domain = "example.com"
CertificateId = "cert-xxxxxxxx"
},
@{
Domain = "www.example.com"
CertificateId = "cert-yyyyyyyy"
}
)
其中 CertificateId 是腾讯云 SSL 证书 ID。可以在腾讯云 SSL 证书控制台看到,也可以通过腾讯云 API/CLI 查询。
如果后续腾讯云续期后生成了新的证书 ID,需要同步更新这里的 CertificateId;如果要做到完全自动识别最新证书,可以再扩展脚本,用 DescribeCertificates 按域名查询最新已签发证书。
PowerShell 脚本
模板脚本放在同目录:
软件\Update-TencentSsl.template.ps1
部署到服务器时,把它复制为:
C:\ssl-auto\Update-TencentSsl.ps1
第一次建议手动运行:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\ssl-auto\Update-TencentSsl.ps1" -EnvFile "C:\ssl-auto\tencent-ssl.env.ps1"
如果脚本能正常下载、解压、复制证书,并且 nginx reload 成功,再注册定时任务。
注册 Windows 定时任务
推荐使用 PowerShell 注册,少踩 schtasks 的引号坑:
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument '-NoProfile -ExecutionPolicy Bypass -File "C:\ssl-auto\Update-TencentSsl.ps1" -EnvFile "C:\ssl-auto\tencent-ssl.env.ps1"'
$trigger = New-ScheduledTaskTrigger -Daily -At 3:00am
Register-ScheduledTask `
-TaskName "AutoUpdateTencentSSL" `
-Action $action `
-Trigger $trigger `
-User "SYSTEM" `
-RunLevel Highest `
-Force
查看任务:
Get-ScheduledTask -TaskName "AutoUpdateTencentSSL"
Get-ScheduledTaskInfo -TaskName "AutoUpdateTencentSSL"
手动跑一次任务:
Start-ScheduledTask -TaskName "AutoUpdateTencentSSL"
nginx 配置
nginx 里固定引用目标证书文件即可:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate conf/key/example.com_bundle.crt;
ssl_certificate_key conf/key/example.com.key;
}
脚本每次只负责把腾讯云 ZIP 包里的 nginx 证书复制成这两个固定文件名:
example.com_bundle.crt
example.com.key
nginx 配置不用跟着证书包文件名变化。
安全边界
- 不要把
SecretId、SecretKey写进公开脚本。 - 不要把
C:\ssl-auto\tencent-ssl.env.ps1提交到 Git。 - 腾讯云 API 密钥建议使用子账号,并只授予 SSL 证书相关权限。
- 证书替换前要先备份旧文件。
nginx.exe -t失败时不能 reload,避免把线上 nginx 切到错误配置。- 日志里不要打印完整密钥。
常见问题
这和 ACME 自动续签有什么区别?
ACME 自动续签是服务器自己向 Let's Encrypt、ZeroSSL 等 CA 申请新证书;这里是腾讯云已经签发好证书,服务器只负责定时下载和安装。
为什么要每天跑?
每天跑一次成本很低,也能确保腾讯云续期完成后,服务器不用等太久就能拿到新证书。脚本可以通过证书内容 hash 判断是否变化,没有变化就跳过 nginx reload。
为什么不用手动复制?
手动复制最容易忘,也容易把 .key、.crt 放错目录。脚本化之后,只要腾讯云证书正常续期,服务器端替换流程就是可重复、可检查的。
参考资料
- 腾讯云 SSL API
DownloadCertificate:下载证书接口会返回 ZIP 的 base64 内容。 - 腾讯云 SSL API 文档:接口域名是
ssl.tencentcloudapi.com,版本为2019-12-05。