本文最后更新于41 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com
阿里云 DNS 实现 Certbot 泛域名证书全自动续期(超详细步骤)
本流程从 “零依赖” 开始,每一步附具体操作、验证方法和注意事项,确保新手也能完成配置,实现证书续期无需手动干预 DNS。
一、准备阿里云 AccessKey(核心前提,100% 必做)
1. 登录阿里云 RAM 控制台
- 打开浏览器,访问 阿里云 RAM 控制台(需登录你的阿里云主账号)。
- 若提示 “实名认证”,先完成实名认证(阿里云 API 调用需实名)。
2. 创建仅用于 DNS 操作的子账号(最小权限原则,安全!)
- 左侧菜单点击 “用户管理”→“创建用户”:
- 用户名:自定义(如
certbot-dns-user
,便于识别用途)。 - 访问方式:仅勾选 “编程访问”(取消 “控制台访问”,避免子账号登录网页)。
- 点击 “确定”,弹出 “用户创建成功” 窗口。
- 用户名:自定义(如
- 保存 AccessKey ID 和 AccessKey Secret:
- 窗口中会显示 “AccessKey ID” 和 “AccessKey Secret”,立即复制到记事本(Secret 仅显示一次,丢失需重新创建)。
- 点击 “关闭”,返回用户列表。
3. 为子账号添加 DNS 操作权限(避免超权风险)
- 在用户列表中,找到刚创建的 certbot-dns-user,点击右侧 “添加权限”:
- 权限策略搜索框输入
AliyunDNSFullAccess
(阿里云官方 DNS 全权限策略)。 - 勾选搜索结果中的
AliyunDNSFullAccess
,点击 “确定”。
- 权限策略搜索框输入
- 验证权限:点击用户名下的 “权限管理”,确认已存在
AliyunDNSFullAccess
权限,否则后续 API 调用会失败。
二、在 A 服务器安装配置阿里云 CLI(证书申请 / 续期的机器)
1. 安装阿里云 CLI(适配 CentOS/Ubuntu 通用)
- 登录 A 服务器(通过 SSH 工具,如 Xshell、FinalShell,确保用
root
账号)。 - 执行安装命令(自动下载并配置环境变量):bash# 下载并安装阿里云 CLI(一行命令)
curl -fsSL https://get.aliyuncli.com | bash - 等待安装完成(约 1-2 分钟,取决于服务器网速)。
2. 配置阿里云 CLI(关联刚创建的 AccessKey)
- 执行配置命令:bashaliyun configure
- 按提示依次输入信息(每输入一项按回车):
Access Key Id
:粘贴第一步保存的 AccessKey ID。Access Key Secret
:粘贴第一步保存的 AccessKey Secret。Default Region Id
:输入阿里云地域(如cn-hangzhou
、cn-beijing
,选离服务器近的地域,不影响功能)。Default Output Format
:直接回车(默认json
格式,无需修改)。
3. 验证 CLI 配置是否成功(关键!失败需重新配置)
- 执行以下命令,测试能否调用阿里云 DNS 接口:bashaliyun dns DescribeDomains
- 预期结果:返回包含你域名(如
tianyong.icu
)的 JSON 数据,无 “权限不足”“InvalidAccessKeyId” 等报错。 - 若报错:
- 若提示 “InvalidAccessKeyId”:检查 AccessKey ID/Secret 是否输错,重新执行
aliyun configure
核对。 - 若提示 “PermissionDenied”:检查子账号是否添加
AliyunDNSFullAccess
权限,回到第一步补充权限。
- 若提示 “InvalidAccessKeyId”:检查 AccessKey ID/Secret 是否输错,重新执行
三、在 A 服务器编写阿里云 DNS 自动验证脚本(核心逻辑)
1. 创建脚本存放目录(规范文件管理,避免混乱)
- 执行命令创建目录(后续所有证书相关脚本都放这里):bash# 创建目录(若已存在会提示,忽略即可)
mkdir -p /opt/certbot/scripts
# 进入目录
cd /opt/certbot/scripts
2. 编写自动验证脚本(逐行复制,避免手敲错误)
- 用 vim 编辑器创建脚本文件:bashvim aliyun_dns.sh
- 按 i 键进入编辑模式,粘贴以下完整脚本(无需修改,脚本会自动适配你的域名):bash#!/bin/bash
# 阿里云 CLI 路径(默认全局安装,无需修改,若提示找不到可改为 /usr/local/bin/aliyun)
ALIYUN_CLI=”aliyun”
# 临时文件:存储 TXT 记录 ID(用于后续删除记录,存放在 /tmp 目录,重启服务器会自动清理)
RECORD_FILE=”/tmp/_acme-challenge.${CERTBOT_DOMAIN}_${CERTBOT_VALIDATION}”
# 检查阿里云 CLI 是否安装成功(避免脚本执行到一半报错)
if ! command -v $ALIYUN_CLI >/dev/null 2>&1; then
echo “错误:未找到阿里云 CLI,请先执行 ‘curl -fsSL https://get.aliyuncli.com | bash’ 安装” 1>&2
exit 1
fi
# 函数:提取主域名(适配多级域名,如 blog.tianyong.icu → 提取为 tianyong.icu)
get_main_domain() {
local DOMAIN=”$1″
# 用 awk 分割域名,取最后两段(通用逻辑,无需修改)
echo “$DOMAIN” | awk -F’.’ ‘NF > 2 { print $(NF-1)”.”$NF; next } { print $0 }’
}
# 分支1:执行“clean”参数(验证完成后,删除 TXT 记录)
if [ “$1” = “clean” ]; then
# 从临时文件读取之前保存的 TXT 记录 ID
RECORD_ID=$(cat “$RECORD_FILE” 2>/dev/null)
# 若记录 ID 存在,执行删除操作
if [ -n “$RECORD_ID” ]; then
$ALIYUN_CLI dns DeleteDomainRecord \
–DomainName “$(get_main_domain “$CERTBOT_DOMAIN”)” \
–RecordId “$RECORD_ID” \
>/dev/null 2>&1 # 静默执行,不输出多余信息
fi
# 删除临时文件(避免残留)
rm -f “$RECORD_FILE”
# 分支2:无参数(验证前,添加 TXT 记录)
else
# 提取主域名(如 tianyong.icu)
MAIN_DOMAIN=$(get_main_domain “$CERTBOT_DOMAIN”)
# 调用阿里云 API 添加 TXT 记录,并提取返回的 RecordId(用于后续删除)
RECORD_ID=$($ALIYUN_CLI dns AddDomainRecord \
–DomainName “$MAIN_DOMAIN” \ # 主域名
–RR “_acme-challenge” \ # 主机记录(固定为 _acme-challenge,Let’s Encrypt 要求)
–Type “TXT” \ # 记录类型(固定为 TXT)
–Value “$CERTBOT_VALIDATION” \# 记录值(Certbot 自动生成的验证字符串)
–TTL 600 \ # 生效时间(600秒=10分钟,阿里云最小支持600)
| grep “RecordId” \ # 过滤返回结果中的 RecordId 字段
| grep -Eo “[0-9]+” \ # 提取 RecordId 的数字部分
)
# 将 RecordId 保存到临时文件(供后续删除用)
echo “$RECORD_ID” > “$RECORD_FILE”
# 等待 DNS 记录全球生效(关键!阿里云 DNS 同步到全球节点需要时间,太短会验证失败)
sleep 30 # 30秒足够,若多次验证失败可改为 60
fi - 按
Esc
键退出编辑模式,输入:wq
并回车(保存并退出vim
)。
3. 给脚本添加执行权限(否则 Certbot 无法调用)
- 执行命令:bashchmod +x /opt/certbot/scripts/aliyun_dns.sh
- 验证权限:执行
ls -l aliyun_dns.sh
,确保权限显示为-rwxr-xr-x
(开头有x
,表示可执行)。
四、修改 Certbot 配置(让续期调用自动脚本)
场景 1:尚未申请证书(首次申请,直接用自动脚本)
- 执行以下命令申请泛域名证书(替换 your-email@example.com 为你的邮箱,用于证书过期提醒):bashcertbot certonly –manual \
–preferred-challenges=dns \ # 强制使用 DNS-01 验证(泛域名必需)
–email your-email@example.com \ # 替换为你的邮箱(如 123456@qq.com)
–server https://acme-v02.api.letsencrypt.org/directory \ # Let’s Encrypt 泛域名证书服务器
–domain tianyong.icu \ # 主域名
–domain “*.tianyong.icu” \ # 泛域名(覆盖所有子域名)
–manual-auth-hook “/opt/certbot/scripts/aliyun_dns.sh” \ # 验证前调用添加 TXT 脚本
–manual-cleanup-hook “/opt/certbot/scripts/aliyun_dns.sh clean” \ # 验证后调用删除 TXT 脚本
–config-dir /opt/certbot/config \ # 证书配置文件存放目录(之前创建的)
–work-dir /opt/certbot/work \ # Certbot 工作目录
–logs-dir /opt/certbot/logs # 日志目录(后续排查问题用) - 执行过程中需确认两次:
- 提示 “是否同意 Let’s Encrypt 的服务条款”:输入
A
并回车(同意)。 - 提示 “是否共享邮箱用于推广”:输入
N
并回车(不共享)。
- 提示 “是否同意 Let’s Encrypt 的服务条款”:输入
- 预期结果:最后显示 “Successfully received certificate”,证书保存到
/opt/certbot/config/live/tianyong.icu/
目录。
场景 2:已申请过证书(仅需修改续期配置,无需重新申请)
- 直接修改之前的续期脚本 renew_and_sync.sh(确保续期时调用自动验证脚本):
- 编辑续期脚本:bashvim /opt/certbot/renew_and_sync.sh
- 找到 “1. 自动续期证书” 部分,补充 –manual、–preferred-challenges=dns 等参数,完整内容如下:bash#!/bin/bash
# 1. 自动续期(调用阿里云自动验证脚本,关键参数不能少)
certbot renew \
–config-dir /opt/certbot/config \ # 原目录不变
–work-dir /opt/certbot/work \ # 原目录不变
–logs-dir /opt/certbot/logs \ # 原目录不变
–quiet \ # 静默执行,无多余输出(适合定时任务)
–manual \ # 启用手动模式(才能调用自定义脚本)
–preferred-challenges=dns \ # 强制 DNS-01 验证
–manual-auth-hook “/opt/certbot/scripts/aliyun_dns.sh” \ # 添加 TXT 记录
–manual-cleanup-hook “/opt/certbot/scripts/aliyun_dns.sh clean” # 删除 TXT 记录
# 2. 同步证书到 B 服务器(原逻辑不变,无需修改)
ssh root@B服务器IP “mkdir -p /etc/letsencrypt/live/tianyong.icu/”
scp -r /opt/certbot/config/live/tianyong.icu/* root@B服务器IP:/etc/letsencrypt/live/tianyong.icu/
# 3. 重启 B 服务器 Nginx(原逻辑不变,无需修改)
ssh root@B服务器IP “docker restart nginx-tianyong || systemctl restart nginx” - 保存退出:按
Esc
,输入:wq
回车。
场景 3:修改定时任务(若之前直接用 Crontab 续期,未用脚本)
- 编辑 Crontab 定时任务:bashcrontab -e
- 找到原续期任务行,补充 –manual、–manual-auth-hook 等参数,完整内容如下(替换 B服务器IP 为实际地址):bash# 每 10 天凌晨 3 点执行续期(时间不变,补充验证参数)
0 3 */10 * * certbot renew \
–config-dir /opt/certbot/config \
–work-dir /opt/certbot/work \
–logs-dir /opt/certbot/logs \
–quiet \
–manual \
–preferred-challenges=dns \
–manual-auth-hook “/opt/certbot/scripts/aliyun_dns.sh” \
–manual-cleanup-hook “/opt/certbot/scripts/aliyun_dns.sh clean” \
–deploy-hook “/opt/certbot/scripts/renew_and_reload_nginx.sh” \ # 原部署钩子不变
>> /var/log/certbot-renew.log 2>&1 # 日志输出不变 - 保存退出:按
Esc
,输入:wq
回车(Crontab 会自动生效,无需重启服务)。
五、测试自动续期(关键!确保后续续期不失败)
1. 执行模拟续期(–dry-run 模式,不实际更新证书)
- 执行以下命令(和续期命令一致,仅多 –dry-run 参数):bashcertbot renew \
–config-dir /opt/certbot/config \
–work-dir /opt/certbot/work \
–logs-dir /opt/certbot/logs \
–dry-run \ # 模拟续期,不修改实际证书
–manual \
–preferred-challenges=dns \
–manual-auth-hook “/opt/certbot/scripts/aliyun_dns.sh” \
–manual-cleanup-hook “/opt/certbot/scripts/aliyun_dns.sh clean”
2. 观察执行过程(确认脚本自动调用)
- 正常流程会显示:
Running manual-auth-hook
:调用脚本添加 TXT 记录。Waiting for verification
:等待 DNS 生效(脚本中sleep 30
的时间)。Running manual-cleanup-hook
:调用脚本删除 TXT 记录。- 最后显示
The dry run was successful
(模拟续期成功)。
3. 验证 DNS 记录自动添加 / 删除(眼见为实)
- 打开阿里云 DNS 控制台(https://dns.console.aliyun.com/),找到tianyong.icu 域名:
- 在脚本执行到
Waiting for verification
时(约 30 秒内),刷新页面,会看到_acme-challenge
的 TXT 记录(存在时间约 30 秒)。 - 等待脚本执行到
Running manual-cleanup-hook
后,再次刷新页面,_acme-challenge
记录消失(自动删除成功)。
- 在脚本执行到
4. 若测试失败,按以下步骤排查
报错信息 | 可能原因 | 解决方法 | |
---|---|---|---|
manual-auth-hook script exited with error code 1 | 脚本无执行权限 | 重新执行 chmod +x /opt/certbot/scripts/aliyun_dns.sh | |
AddDomainRecord failed: PermissionDenied | AccessKey 权限不足 | 回到第一步,确认子账号已添加 AliyunDNSFullAccess 权限 | |
DNS problem: NXDOMAIN looking up TXT for _acme-challenge.tianyong.icu | DNS 生效时间不足 | 修改脚本中 sleep 30 为 sleep 60 ,重新测试 | |
aliyun: command not found | CLI 未安装或环境变量未加载 | 重新执行 curl -fsSL [https://get.aliyuncli.com](https://get.aliyuncli.com/) | bash ,并退出 SSH 重新登录 |
六、最终确认(确保全自动续期生效)
- 检查证书目录:执行
ls /opt/certbot/config/live/tianyong.icu/
,确认有fullchain.pem
(证书链)和privkey.pem
(私钥)。 - 检查定时任务:执行
crontab -l
,确认续期任务包含 `–manual-auth-h