1 前言
在访问我的博客时,发现我的图床又又又挂掉了,肯定是ssl证书到期,导致https访问出问题了(已经很多次了),本以为还能在阿里云上申请个人免费测试证书,续个命;登上阿里云控制台 一看,发现个人免费测试证书无了(应该是当时从oss那里的跳转入口不对,以为没有了,直接跳转到下面的这个付费版页面了)。

刚刚为了严谨,在阿里云控制台又走了一遍,发现还在,申请流程如下



唉,为了这碗醋,包了顿饺子;为了这个脚本,写了这篇博客
2 证书自动化申请、部署的条件与流程
2.1 准备工作
- RAM 访问密钥(AccessKey): 准备一个阿里云 RAM 子账号的
Api_Key和Api_Secret。 - 核心授权: 该子账号必须同时具备以下三项权限:
AliyunDNSFullAccess(用于向你的域名自动写入 DNS 解析记录以通过 ACME 验证)。AliyunOSSFullAccess(用于将证书推送到指定的存储桶)。AliyunYundunCertFullAccess具备yundun-cert:CreateSSLCertificate(数字证书管理服务)的权限。
其中,不要忘记给这个AliyunYundunCertFullAccess权限,因为 OSS 的 put-cname 接口在接收到你的托管证书时,会在底层将证书托管到阿里云证书服务中,没有这个权限会直接触发 403 拒绝。
2.2 流程概述
首先执行 aliyun cli 和 acme.sh 的安装;
然后,为了防止
脚本
未能完整执行成功,多次向 ZeroSSL 申请时,触发申请时间限制,对acme已经申请到的证书签发时间使用openssl与系统时间进行对比分析,进而划分两个路径:
-
如果证书签发未满 60 天(2个月),说明证书依然非常新。脚本将直接跳过向云端 CA 申请的步骤,直接提取本地证书发起部署。避免 ZeroSSL 重复申请导致延时。
-
如果证书超过 60 天,脚本才会自动向 CA 发起续期(Renew)申请。
最后,上传阿里云平台部署,基于最新 API 传参:动态将证书内容塞入最新规范的 BucketCnameConfiguration XML 结构中,通过新版 aliyun ossutil api put-cname 命令和 --cname-configuration file:// 传参,完成一键全自动托管部署。
阿里云oss控制台查看ssl证书,成功!

3 完整脚本
完整脚本如下,直接复制粘贴
#!/bin/bash
# ==============================================================================
# 脚本名称: acme_deploy_ssl_to_aliyun_oss.sh
# 适用环境: 完美适配最新一代 aliyun ossutil api 命令与自动化证书年龄检测
# ==============================================================================
# ==================== 【配置区域 - 请务必根据实际情况修改】 ====================
# 1. 阿里云 RAM 访问密钥(需具备 DNS、OSS 以及 yundun-cert 的相关权限)
export Ali_Key="cc&uu"
export Ali_Secret="https://caibucai.top"
# 2. 证书申请域名(即你绑定在 OSS 的自定义域名)
DOMAIN="你的oss绑定域名"
# 3. 接收证书过期通知的邮箱
EMAIL="cc&uu@gmail.com"
# 4. 阿里云 OSS 存储桶信息
OSS_BUCKET="bucket_name" # 注意:严格填写纯粹的 Bucket 名字,不要带后缀
OSS_REGION="cn-hangzhou" # 存储桶所在的区域 ID
FORCE_RENEW=false # 是否强制重新申请证书(true/false)
# ==============================================================================
echo "[1/4] 开始检查并安装 Aliyun CLI 工具..."
if ! command -v aliyun &> /dev/null; then
echo "未检测到 aliyun cli,正在下载并安装..."
curl -L -o aliyun-cli.tgz https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz
tar -zxvf aliyun-cli.tgz
sudo mv aliyun /usr/local/bin/
rm -f aliyun-cli.tgz
echo "Aliyun CLI 安装成功!"
else
echo "Aliyun CLI 已存在,跳过安装。"
fi
echo "[2/4] 动态配置高级版 Aliyun CLI 凭证..."
aliyun configure set \
--profile current \
--mode AK \
--region "$OSS_REGION" \
--access-key-id "$Ali_Key" \
--access-key-secret "$Ali_Secret"
echo "[3/4] 开始检查并安装 acme.sh..."
if [ ! -f "$HOME/.acme.sh/acme.sh" ]; then
curl https://gh-proxy.org/https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | sh -s -- --install-online -m $EMAIL
source "$HOME/.bashrc" || true
else
echo "acme.sh 已存在,跳过安装。"
fi
# 设置默认 CA 为 ZeroSSL(可根据习惯调整为 letsencrypt)
"$HOME/.acme.sh/acme.sh" --set-default-ca --server zerossl
# 临时证书导出目录
CERT_DIR="/tmp/oss_cert_out"
mkdir -p "$CERT_DIR"
# acme.sh 默认的证书存放路径(自动兼容 ECC 与普通路径)
ACME_CERT_PATH="$HOME/.acme.sh/${DOMAIN}_ecc/fullchain.cer"
if [ ! -f "$ACME_CERT_PATH" ]; then
ACME_CERT_PATH="$HOME/.acme.sh/${DOMAIN}/fullchain.cer"
fi
echo "===================================================="
echo "🎯 开始检查域名 [ $DOMAIN ] 的本地证书状态..."
echo "===================================================="
NEED_ISSUE=true
# ==============================================================================
# 逻辑检查:检查本地是否存在未满 2 个月(60天)的最新证书
# ==============================================================================
if [ -f "$ACME_CERT_PATH" ]; then
echo "发现本地已存在历史证书,正在计算签发时间..."
# 获取证书的签发时间戳(秒)
START_DATE=$(openssl x509 -in "$ACME_CERT_PATH" -noout -startdate | cut -d= -f2)
START_TIME_STAMP=$(date -d "$START_DATE" +%s)
# 获取当前系统时间戳(秒)
CURRENT_TIME_STAMP=$(date +%s)
# 精准计算已经过去了多少天(一天为 86400 秒)
AGE_DAYS=$(( (CURRENT_TIME_STAMP - START_TIME_STAMP) / 86400 ))
echo "💡 该本地证书已签发了 $AGE_DAYS 天。"
if [ "$AGE_DAYS" -lt 60 ] && [ "$FORCE_RENEW" = false ]; then
echo "✅ 证书签发时间未满 60 天(2个月),无需向 ZeroSSL 重复申请。"
echo "🚀 脚本将直接提取本地证书并推送到阿里云 OSS 部署。"
NEED_ISSUE=false
else
if [ "$FORCE_RENEW" = true ]; then
echo "⚠️ 已开启强制重新申请 (FORCE_RENEW=true)。"
else
echo "⌛ 证书已签发超过 60 天,准备向 CA 发起更新申请。"
fi
fi
else
echo "ℹ️ 本地未检测到历史证书,将首次发起申请流程。"
fi
# ==============================================================================
# 步骤 [4/4]:执行证书申领(如果需要)与最新 API 推送
# ==============================================================================
if [ "$NEED_ISSUE" = true ]; then
echo ""
echo "正在向证书局申请新证书..."
# 安全捕获命令,防止 ZeroSSL 熔断直接导致脚本硬崩溃
if ! "$HOME/.acme.sh/acme.sh" --issue --dns dns_ali -d "$DOMAIN"; then
echo "❌ 错误: 证书申请由于网络或 ZeroSSL 接口限制失败!"
echo "💡 容错提示: 由于本地已有历史证书,我们将强制尝试用本地旧证书为您同步,防止线上直接断流。"
echo "正在跳过报错,尝试提取本地已有证书..."
fi
else
echo ""
echo "⏭️ 已跳过申请步骤。"
fi
echo ""
echo "正在从 acme.sh 提取证书..."
"$HOME/.acme.sh/acme.sh" --install-cert -d "$DOMAIN" \
--key-file "$CERT_DIR/privkey.key" \
--fullchain-file "$CERT_DIR/fullchain.pem"
XML_FILE="/tmp/oss_cname_final.xml"
echo "正在组装阿里云官方最新规范的 XML 配置文件..."
cat << EOF > "$XML_FILE"
<?xml version="1.0" encoding="UTF-8"?>
<BucketCnameConfiguration>
<Cname>
<Domain>$DOMAIN</Domain>
<CertificateConfiguration>
<Certificate>$(cat $CERT_DIR/fullchain.pem)</Certificate>
<PrivateKey>$(cat $CERT_DIR/privkey.key)</PrivateKey>
<Force>true</Force>
</CertificateConfiguration>
</Cname>
</BucketCnameConfiguration>
EOF
# 安全擦除临时导出的明文证书目录
rm -rf "$CERT_DIR"
echo "正在执行 aliyun ossutil api put-cname 同步到云端..."
# 严格适配最新版 V2 命令行参数:--cname-configuration file://...
if aliyun ossutil api put-cname --bucket "$OSS_BUCKET" --cname-configuration "file://$XML_FILE" --region "$OSS_REGION"; then
echo "===================================================="
echo "🎉 完美成功!SSL 证书已成功在阿里云 OSS 部署生效!"
echo "安全访问域名: https://$DOMAIN"
echo "===================================================="
else
echo "❌ 错误: 推送证书到阿里云 OSS 失败,请检查 RAM 密钥权限或存储桶名称是否正确。"
fi
# 无论成功或失败,都必须清理掉带有敏感私钥的临时配置文件
rm -f "$XML_FILE"
赋予执行权限并运行即可:
chmod +x acme_deploy_ssl_to_aliyun_oss.sh
./acme_deploy_ssl_to_aliyun_oss.sh
再配合个定时任务,执行,即可实现自动化申请与部署。
参考
-
ACME.sh 官方开源 Wiki 探讨了关于利用阿里云 DNS API(
dns_ali)进行自动化验证 -
aliyun cli 有效内容很少,直接在终端使用 -h 获取提示信息