✍️ 引言
在日常运维工作中,SSL 证书的更新是一项琐碎却不得不做的任务。尤其是 Let's Encrypt 或 ZeroSSL 提供的免费证书,有效期只有 90 天,一旦忘记续期,用户将面临 HTTPS 无法访问、浏览器提示风险等严重问题。
而运维团队往往人少事多,每三个月一次的证书更换就像一颗定时炸弹,一年的收费证书又好贵啊,为了缓解这个问题,我们选择使用开源工具 acme.sh
,自动申请/续签免费证书,并通过 DNS API 完成验证,无需手动操作。
本篇文章将完整记录如何在 腾讯云环境中部署 acme.sh
,并实现自动申请泛域名 SSL 证书的过程。
📦 环境准备
- 腾讯云服务器(CentOS/Ubuntu)
- 域名托管在腾讯云 DNS(DNSPod)
- Docker 部署的 Nginx,挂载路径为
/datas/docker/conf/nginx/ssl
🧰 安装 acme.sh
# 手动运行 acme.sh 的安装流程 # 华为可能下载不了 curl https://get.acme.sh > get_acme.sh && sh get_acme.sh && source .bashrc #查看版本 acme.sh --version # 升级 acme.sh --upgrade # 安装 acme.sh --install --force 申请证书 需要绑定邮箱 ~/.acme.sh/acme.sh --register-account -m mrc2017@foxmail.com
华为云的问题有点多,不多写了,遇故障问ai
##注意,华为云下载不了的,需要你手动去github下载 curl -L https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh > acme.sh sh acme.sh --install --force #华为云还缺少这个插件 curl -o ~/.acme.sh/dnsapi/dns_huaweicloud.sh https://raw.githubusercontent.com/acmesh-official/acme.sh/master/dnsapi/dns_huaweicloud.sh
🔐 设置腾讯云 API 密钥
登录获取:
- 打开:腾讯云 API 密钥管理
- 获取
SecretId
和SecretKey
方式一: 使用主账号 API 密钥
- 登录 腾讯云控制台,进入 访问管理 页面,单击左侧菜单栏的 访问密钥,进入 API 密钥管理页面。
- 单击新建密钥,创建 API 密钥,并记录保存 SecretId 和 SecretKey。
方式二:使用子账号 API 密钥
步骤一:新建权限策略
- 登录 腾讯云控制台,进入 访问管理 页面,单击左侧菜单栏的 策略,进入策略页面,并点击新建自定义策略。
}}
- 选择按策略语法创建 > 空白模板,填写基本信息,并将策略语法修改为以下内容,并单击完成。
{ "statement": [ { "action": [ "dnspod:DescribeRecordFilterList", "dnspod:DescribeRecordList", "dnspod:CreateRecord", "dnspod:DeleteRecord" ], "effect": "allow", "resource": [ "*" ] } ], "version": "2.0" }
}}
步骤二:新建子账号并关联权限策略
- 登录 腾讯云控制台,进入 访问管理 页面,单击左侧菜单栏的 用户列表,进入用户列表页面,并单击新建用户。
- 在新建用户页面,选择快速创建,填写用户信息,并选择编程访问。
- 在快速新建用户页面,填写用户信息,并选择编程访问。
}}
- 配置用户权限,仅选择刚刚创建的权限策略,并单击确定。
- 单击创建用户,完成子账号创建。
- 策略那边可以找的到“ssl”的策略,然后添加到子账户即可
}} 8.记录保存 SecretId 和 SecretKey。
设置环境变量:
1.将获取到的 SecretId 和 SecretKey 导入环境变量中,以便 acme.sh 调用。
export Tencent_SecretId="<Your SecretId>" export Tencent_SecretKey="<Your SecretKey>" # 可选:永久保存到 ~/.bashrc source ~/.bashrc
🌍 切换 CA 为 Let's Encrypt(推荐)
acme.sh --set-default-ca --server letsencrypt
🧾 申请泛域名 SSL 证书
acme.sh --issue --dns dns_tencent -d kkxl95.cn -d *.kkxl95.cn
成功后输出类似:
Your cert is in: /root/.acme.sh/yourdomain.com_ecc/yourdomain.com.cer Your cert key is in: /root/.acme.sh/yourdomain.com_ecc/yourdomain.com.key ...
如果报错:
[root@WWW_49.235.46.223 15:50:25~]# acme.sh --issue --dns dns_tencent -d kkxl95.cn -d *.kkxl95.cn [Fri Jul 11 03:50:54 PM CST 2025] Using CA: https://acme.zerossl.com/v2/DV90 [Fri Jul 11 03:50:54 PM CST 2025] Multi domain='DNS:kkxl95.cn,DNS:*.kkxl95.cn' [Fri Jul 11 03:51:05 PM CST 2025] Getting webroot for domain='kkxl95.cn' [Fri Jul 11 03:51:05 PM CST 2025] Getting webroot for domain='*.kkxl95.cn' [Fri Jul 11 03:51:05 PM CST 2025] Adding TXT value: zDuEl2VJsqn5AL5a1iawP4JGXyi5KpvLFXNCs-zvzUY for domain: _acme-challenge.kkxl95.cn [Fri Jul 11 03:51:07 PM CST 2025] The TXT record has been successfully added. [Fri Jul 11 03:51:07 PM CST 2025] Adding TXT value: dFs5212rNwp2KXbkSjgb3oJKU7K7SIeJ_BNIMiOLvRw for domain: _acme-challenge.kkxl95.cn [Fri Jul 11 03:51:09 PM CST 2025] The TXT record has been successfully added. [Fri Jul 11 03:51:09 PM CST 2025] Let's check each DNS record now. Sleeping for 20 seconds first. [Fri Jul 11 03:51:30 PM CST 2025] You can use '--dnssleep' to disable public dns checks. [Fri Jul 11 03:51:30 PM CST 2025] See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck [Fri Jul 11 03:51:30 PM CST 2025] Checking kkxl95.cn for _acme-challenge.kkxl95.cn [Fri Jul 11 03:51:30 PM CST 2025] Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 35 [Fri Jul 11 03:51:40 PM CST 2025] Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 28 [Fri Jul 11 03:51:40 PM CST 2025] Success for domain kkxl95.cn '_acme-challenge.kkxl95.cn'. [Fri Jul 11 03:51:40 PM CST 2025] Checking kkxl95.cn for _acme-challenge.kkxl95.cn [Fri Jul 11 03:51:40 PM CST 2025] Success for domain kkxl95.cn '_acme-challenge.kkxl95.cn'. [Fri Jul 11 03:51:40 PM CST 2025] All checks succeeded [Fri Jul 11 03:51:40 PM CST 2025] Verifying: kkxl95.cn [Fri Jul 11 03:51:51 PM CST 2025] Processing. The CA is processing your order, please wait. (1/30) [Fri Jul 11 03:51:57 PM CST 2025] Success [Fri Jul 11 03:51:57 PM CST 2025] Verifying: *.kkxl95.cn [Fri Jul 11 03:52:10 PM CST 2025] Processing. The CA is processing your order, please wait. (1/30) [Fri Jul 11 03:52:25 PM CST 2025] Success [Fri Jul 11 03:52:25 PM CST 2025] Removing DNS records. [Fri Jul 11 03:52:25 PM CST 2025] Removing txt: zDuEl2VJsqn5AL5a1iawP4JGXyi5KpvLFXNCs-zvzUY for domain: _acme-challenge.kkxl95.cn [Fri Jul 11 03:52:28 PM CST 2025] Successfully removed [Fri Jul 11 03:52:28 PM CST 2025] Removing txt: dFs5212rNwp2KXbkSjgb3oJKU7K7SIeJ_BNIMiOLvRw for domain: _acme-challenge.kkxl95.cn [Fri Jul 11 03:52:30 PM CST 2025] Successfully removed [Fri Jul 11 03:52:30 PM CST 2025] Verification finished, beginning signing. [Fri Jul 11 03:52:30 PM CST 2025] Let's finalize the order. [Fri Jul 11 03:52:30 PM CST 2025] Le_OrderFinalize='https://acme.zerossl.com/v2/DV90/order/mzBVxRjGTQglf6wlcL6ptQ/finalize' [Fri Jul 11 03:52:30 PM CST 2025] Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 35 [Fri Jul 11 03:52:30 PM CST 2025] Signing failed. Finalize code was not 200. [Fri Jul 11 03:52:30 PM CST 2025] [Fri Jul 11 03:52:30 PM CST 2025] Please add '--debug' or '--log' to see more information. [Fri Jul 11 03:52:30 PM CST 2025] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh
分析
DNS 验证是 成功的,但最终的 证书签发阶段失败了,原因如下: ❗ 报错核心:
[Fri Jul 11 03:52:30 PM CST 2025] Signing failed. Finalize code was not 200. [Fri Jul 11 03:52:30 PM CST 2025] Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 35
🔴 curl error code: 35 代表:SSL 连接失败 通常是由于系统 网络问题、SSL库版本问题,或 ZeroSSL 无法连接造成的 ✅ 前面流程是成功的部分(你做对了): ✅ 成功使用 dns_tencent 验证了 DNS 记录 ✅ 成功添加并清除了 _acme-challenge 的 TXT ✅ 域名验证通过 ❌ 最后一步向 ZeroSSL 请求签发证书时失败(网络/SSL问题) ✅ 推荐立即改回 Let's Encrypt CA(更快更稳,不用注册)
修复
# 执行以下命令切换 CA 为 Let's Encrypt: acme.sh --set-default-ca --server letsencrypt #然后重新申请: acme.sh --issue --dns dns_tencent -d kkxl95.cn -d '*.kkxl95.cn'
- 运行后,acme.sh 将自动为您的域名申请证书,并将证书文件保存在~/.acme.sh/example.com/目录下,并且会自动为您的域名配置证书自动续期任务,无需手动续期。
[Fri Jul 11 03:54:41 PM CST 2025] Your cert is in: /root/.acme.sh/kkxl95.cn_ecc/kkxl95.cn.cer [Fri Jul 11 03:54:41 PM CST 2025] Your cert key is in: /root/.acme.sh/kkxl95.cn_ecc/kkxl95.cn.key [Fri Jul 11 03:54:41 PM CST 2025] The intermediate CA cert is in: /root/.acme.sh/kkxl95.cn_ecc/ca.cer [Fri Jul 11 03:54:41 PM CST 2025] And the full-chain cert is in: /root/.acme.sh/kkxl95.cn_ecc/fullchain.cer
放到指定目录,因为我用的是docker部署的Nginx,所以生成证书就行了
acme.sh --install-cert -d kkxl95.cn \ --key-file /datas/docker/conf/nginx/ssl/kkxl95.cn.key \ --fullchain-file /datas/docker/conf/nginx/ssl/kkxl95.cn.fullchain.cer \ --cert-file /datas/docker/conf/nginx/ssl/kkxl95.cn.cer \ --ca-file /datas/docker/conf/nginx/ssl/kkxl95.cn.ca.cer
📂 Nginx配置,需要跟你的文件路径保持一致!
server { listen 443 ssl; server_name kkxl95.cn; ssl_certificate /etc/nginx/ssl/kkxl95.cn.fullchain.cer; ssl_certificate_key /etc/nginx/ssl/kkxl95.cn.key; return 301 http://$host$request_uri; } # 启动容器 docker restart izone_nginx
🔁 自动续期与自动重启(可选)
acme.sh 会自动创建定时任务,默认每天检查证书是否需要续签:
crontab -l
如你希望续签后自动重启 Docker 容器,可以这样设置:
acme.sh --install-cert -d yourdomain.com --key-file /datas/docker/conf/nginx/ssl/yourdomain.com.key --fullchain-file /datas/docker/conf/nginx/ssl/yourdomain.com.fullchain.cer --reloadcmd "docker restart nginx_container_name"
🧠 小结
- ✅ 免费证书有时效性,但配合 acme.sh 可实现全自动更新
- ✅ DNS 验证方式适合泛域名和无需80端口的场景
- ✅ 部署一次,后续只需定期重启服务即可生效
📢 运维的心声
“我们要维护的不是证书,而是用户的信任。”
免费证书虽然诱人,但每 90 天就更新一次的设定实在太苛刻。acme.sh
就像运维人员的自动化“螺丝刀”,省心省力,不再担心“证书过期网站挂了”这类低级事故。
📌 建议所有 HTTPS 项目尽早引入 acme.sh 自动部署机制,把精力留给更重要的任务。
如有其他云平台(阿里云、Cloudflare、百度云)场景,也可以参考 acme.sh 支持的 完整 DNS 插件列表。
版权声明:如无特殊说明,文章均为本站原创,转载请注明出处
本文链接:http://kkxl95.cn/article/0X4B7wiid1f8YwFColOi/