· server · 7 min 阅读
使用 acme.sh 通过 CNAME 申请域名证书
当 DNS 不在自己手里时,如何通过 CNAME 接力验证免费申请 Let's Encrypt 证书?手把手教你用 acme.sh 解决无 DNS 权限场景下的证书签发难题。
前言
在申请 Let’s Encrypt 证书时,最常用的方式是 DNS-01 校验:在域名解析中添加一条 _acme-challenge 的 TXT 记录,由 ACME 服务器通过 DNS 查询完成域名所有权校验。
但在实际场景中,我们经常会遇到以下问题:
- 域名托管在第三方平台(如 Cloudflare、企业内部 DNS),无法直接修改解析记录;
- 想要集中管理多个域名的证书,但每个域名对应不同的 DNS 服务商;
- 想为子域名申请证书,但主域的 DNS 不在自己手里。
此时可以使用 acme.sh 的 CNAME 接力验证 功能:把 _acme-challenge 记录通过 CNAME 指向另一个你有完整控制权的域名,由该域名的 DNS API 完成 ACME 校验,从而绕过主域 DNS 的限制。
原理说明
acme.sh 通过 --challenge-alias 参数实现 CNAME 接力验证,整体流程如下:
example.com 的 _acme-challenge → CNAME → _acme-challenge.x1.example2.com
↓
Let's Encrypt 沿 CNAME 查询到 example2.com
↓
acme.sh 通过腾讯云 API 在 x1.example2.com 下
添加 _acme-challenge TXT 记录
↓
Let's Encrypt 校验通过 → 证书签发成功 简单来说:
example.com:你想要申请证书的域名(没有 DNS 控制权);example2.com:你拥有完整控制权的域名(用于添加 TXT 记录);x1.example2.com:example2.com下任意一个子域名,作为校验的”中转站”。
前提条件
- 一台 Linux 服务器(Debian/Ubuntu/CentOS 均可);
- 一个自己有 DNS API 权限的域名(本文以腾讯云为例);
- 在「主域」(
example.com) 的 DNS 中添加一条CNAME记录的能力(虽然拿不到完整权限,但至少能加CNAME,这是绝大多数 DNS 服务商都允许的)。
操作步骤
1. 在主域 DNS 中添加 CNAME 记录
登录 example.com 所在的 DNS 服务商,添加以下记录:
| 主机记录 | 记录类型 | 记录值 |
|---|---|---|
| _acme-challenge.example.com | CNAME | _acme-challenge.x1.example2.com |
说明
如果同时为www.example.com申请证书,也需要为它添加一条 CNAME 记录,指向相同的_acme-challenge.x1.example2.com。
2. 安装 acme.sh
# 国内服务器访问 GitHub 受限,建议先配置代理
export https_proxy=http://your-proxy:port
curl https://get.acme.sh | sh -s email=my@example.com
# 使 acme.sh 命令立即生效
source ~/.bashrc 关于
该邮箱用于接收证书到期提醒、Let’s Encrypt 账号恢复等通知,建议使用真实邮箱。
3. 切换默认 CA 为 Let’s Encrypt
acme.sh --set-default-ca --server letsencrypt 为什么要切换?
acme.sh 默认 CA 是 ZeroSSL,部分场景下 Let’s Encrypt 兼容性更好,且国内使用更广泛。
4. 配置腾讯云 DNS API
前往 腾讯云 API 密钥管理 创建 SecretId 和 SecretKey(至少需要 DNSPod 的解析权限),然后执行:
export Tencent_SecretId="AKIDxxxxxxxxxxxxxxxxxxxxxxxx"
export Tencent_SecretKey="xxxxxxxxxxxxxxxxxxxxxxxx"
# 写入 ~/.bashrc,避免重启服务器后失效
echo 'export Tencent_SecretId="AKIDxxxxxxxxxxxxxxxxxxxxxxxx"' >> ~/.bashrc
echo 'export Tencent_SecretKey="xxxxxxxxxxxxxxxxxxxxxxxx"' >> ~/.bashrc ⚠️ 注意:必须使用腾讯云 API 密钥,不能使用 DNSPod Token
腾讯云 API 控制台创建的密钥是SecretId+SecretKey组合;如果误用了 DNSPod 的Token,会报invalid dns api错误。
5. 签发证书
acme.sh --issue \
--dns dns_tencent \
-d example.com \
-d "*.example.com" \
--challenge-alias x1.example2.com 参数说明:
--dns dns_tencent:使用腾讯云 DNS API 添加校验记录;-d:要申请证书的域名(支持多个,*.example.com表示通配符);--challenge-alias:指定用于接力校验的子域名(必须在腾讯云 DNS 中存在)。
6. 安装证书到指定路径
acme.sh --install-cert -d example.com \
--cert-file /etc/nginx/ssl/cert.pem \
--key-file /etc/nginx/ssl/key.pem \
--fullchain-file /etc/nginx/ssl/fullchain.pem \
--reloadcmd "docker exec nginx nginx -s reload" 关于
--reloadcmd
- 推荐使用
docker exec nginx nginx -s reload热加载,服务不会中断;- 不要使用
docker restart nginx,这会导致服务短暂不可用;- 如果不是容器化部署,可以改成
systemctl reload nginx。
自动续期与验证
acme.sh 安装时会自动创建 cron 续期任务(每天凌晨随机时间检查一次,到期前 60 天自动续期),通常无需额外配置。可以通过以下命令验证:
# 查看当前所有证书及其到期时间
acme.sh --list
# 查看指定证书的详细信息
acme.sh --info -d example.com
# 手动强制续期测试(不改变实际有效期)
acme.sh --renew -d example.com --force
# 查看 cron 续期任务
crontab -l | grep acme 证书签发后,建议:
- 浏览器访问
https://example.com,确认证书已生效; - 使用 SSL Labs 等在线工具检测证书链配置是否完整。
常见问题
报错 Invalid challenge alias
可能原因:
_acme-challenge.example.com的 CNAME 记录尚未生效(DNS 缓存一般 5~30 分钟);- CNAME 记录配置错误,请检查主机记录是否漏了
_; _acme-challenge.x1.example2.com在腾讯云 DNS 中不存在,需要先在腾讯云控制台添加这条主机记录(任意值都可以)。
报错 dns api error: com.tencentcloudapi
请检查:
Tencent_SecretId和Tencent_SecretKey是否正确;- API 密钥是否具备 DNSPod 解析权限;
- 服务器能否访问
tencentcloudapi.com(国内服务器一般无问题,海外服务器可能需要代理)。
证书签发成功但浏览器提示「不安全」
通常是证书链不完整导致,请确认:
- Nginx 配置中使用了
fullchain.pem(包含中间证书),而不是cert.pem(只有叶子证书); - Nginx 重载配置正确,没有缓存旧的证书文件。
是否支持申请通配符证书?
支持。直接在签发命令中添加 -d "*.example.com" 即可,CNAME 记录共用同一条即可。