闲时
  • 首页
  • 归档
  • 搜索
  • 夜间模式
    ©2020-2026  我的技术记录 主题 OneBlog

    我的技术闲时记录

    搜索
    标签
    # AIGC # SSL # CDN # 学习 # 土力学 # 脚本 # 备份 # 数据库 # 群晖 # FFmpeg

    火山引擎全站加速证书自动更新脚本实践

    2026.05.14 / 1 k 阅读 / 0 评论 / 4529 字

    火山引擎全站加速证书自动更新脚本实践

    阅读 1 k 评论 0 发表于2026.05.14

    背景

    火山云全站加速配置SSL证书,手动上传并绑定证书的过程虽然简单,但多域名重复操作既繁琐又容易出错。于是决定写一个自动化脚本,利用火山引擎 CLI 工具(ve)完成证书上传与绑定的全流程。

    工具选型与思路

    火山引擎提供了统一的命令行工具 ve,支持 CDN、DCDN 等多个服务。一开始查看了 DCDN 相关的命令:

    ve dcdn CreateCertBind --help
    

    发现 CreateCertBind 需要一个已存在于证书中心的 CertId,而不能直接传递证书文件内容。这意味着必须先将证书上传到火山引擎的证书中心,拿到 CertId 后再绑定到 DCDN 域名。

    庆幸的是,ve cdn AddCertificate 命令可以将证书上传至火山引擎证书中心(设置 Source 为 volc_cert_center),并且返回的 CertId 可以在 DCDN 中直接使用。这样一来,流程就清晰了:

    1. 读取本地证书文件(fullchain.pem 和 privkey.pem)
    2. 调用 AddCertificate 上传,获取 CertId(若证书已存在则复用)
    3. 调用 CreateCertBind 将证书绑定到 DCDN 域名

    遇到的两个坑

    1. 通配符域名不被 DCDN 接受

    一开始脚本中的 DomainNames 写成了 ["example.com", "*.example.com"],执行后报错:

    DomainNotExist: Domain Name [*.example.com] does not exist
    

    通过 ve dcdn ListDomainConfig 查看实际已添加的加速域名,发现 DCDN 控制台并不接受 *.example.com 这样的通配符形式。实际存在的域名是 example.com、sub.example.com 以及一个以点开头的特殊域名 .example.com(可能是历史原因或内部标识)。因此最终使用的域名列表需要与实际配置完全一致。

    2. 错误响应的解析路径不一致

    ve cdn AddCertificate 的错误信息位于 .ResponseMetadata.Error,而 ve dcdn CreateCertBind 的错误信息却直接在根节点 .Error 中。最初脚本只检查了 .ResponseMetadata.Error,导致 CreateCertBind 明明失败了,脚本却输出“绑定成功”。修正后同时检查两个可能的路径。

    最终脚本

    以下脚本实现了自动上传证书并绑定到 DCDN 域名。使用时请根据实际情况修改证书存放目录、日志目录以及目标域名列表。

    #!/bin/bash
    #set -xv
    
    log_date() {
        date '+[%Y/%m/%d %H:%M:%S]'
    }
    
    # 配置 - 请按实际修改
    CERT_STORE_DIR="/path/to/your/certificates"
    LOG_DIR="/path/to/log"
    mkdir -p "$LOG_DIR"
    exec > >(tee -a "$LOG_DIR/cert.log") 2>&1
    
    echo "$(log_date) 脚本开始执行"
    
    # 加载证书内容
    cert_content=$(cat "$CERT_STORE_DIR/fullchain.pem")
    key_content=$(cat "$CERT_STORE_DIR/privkey.pem")
    
    echo "$(log_date) 证书内容长度: ${#cert_content}"
    echo "$(log_date) 私钥内容长度: ${#key_content}"
    
    # 1. 上传证书到火山引擎证书中心
    upload_json_request() {
        jq -n \
            --arg cert "$cert_content" \
            --arg key "$key_content" \
            '{
                "Source": "volc_cert_center",
                "CertType": "server_cert",
                "Certificate": $cert,
                "PrivateKey": $key
            }'
    }
    
    echo "$(log_date) 正在上传证书到火山引擎证书中心..."
    response=$(ve cdn AddCertificate --body "$(upload_json_request)")
    
    if echo "$response" | jq -e '.ResponseMetadata.Error' > /dev/null 2>&1; then
        error_code=$(echo "$response" | jq -r '.ResponseMetadata.Error.Code')
        if [ "$error_code" = "InvalidParameter.Certificate.Duplicated" ]; then
            # 证书已存在时从错误消息中提取已有证书ID
            cert_id=$(echo "$response" | jq -r '.ResponseMetadata.Error.Message | capture("ID为 (?<id>[^。]+)。") | .id')
            echo "$(log_date) 证书已存在,使用已有证书ID: $cert_id"
        else
            error_msg=$(echo "$response" | jq -r '.ResponseMetadata.Error.Message')
            echo "$(log_date) 上传失败: $error_msg"
            exit 1
        fi
    else
        request_id=$(echo "$response" | jq -r '.ResponseMetadata.RequestId')
        cert_id=$(echo "$response" | jq -r '.Result.CertId')
        echo "$(log_date) 上传成功,RequestId: $request_id"
        echo "$(log_date) 证书ID: $cert_id"
    fi
    
    # 2. 绑定证书到 DCDN 域名(按实际域名列表修改)
    deploy_json_request() {
        jq -n \
            --arg cert_id "$cert_id" \
            '{
                "CertSource": "volc",
                "CertId": $cert_id,
                "DomainNames": ["example.com", "sub.example.com", ".example.com"]
            }'
    }
    
    echo "$(log_date) 正在将证书绑定到全站加速域名..."
    response=$(ve dcdn CreateCertBind --body "$(deploy_json_request)")
    
    # 增强错误检测:同时检查根级 .Error 和 .ResponseMetadata.Error
    if echo "$response" | jq -e '.Error' > /dev/null 2>&1 || echo "$response" | jq -e '.ResponseMetadata.Error' > /dev/null 2>&1; then
        error_msg=$(echo "$response" | jq -r '.Error.Message // .ResponseMetadata.Error.Message')
        echo "$(log_date) 绑定失败: $error_msg"
        exit 1
    else
        request_id=$(echo "$response" | jq -r '.ResponseMetadata.RequestId // "unknown"')
        echo "$(log_date) 绑定成功,RequestId: $request_id"
        exit 0
    fi
    

    执行效果

    脚本执行时会输出详细日志:

    [2026/05/19 14:38:06] 脚本开始执行
    [2026/05/19 14:38:06] 证书内容长度: 2864
    [2026/05/19 14:38:06] 私钥内容长度: 226
    [2026/05/19 14:38:06] 正在上传证书到火山引擎证书中心...
    [2026/05/19 14:38:11] 上传成功,RequestId: xxx
    [2026/05/19 14:38:11] 证书ID: cert-xxxx
    [2026/05/19 14:38:11] 正在将证书绑定到全站加速域名...
    [2026/05/19 14:38:15] 绑定成功,RequestId: yyy
    

    如果证书已经存在,会直接复用原有证书 ID,避免重复上传。

    总结

    通过结合 ve cdn AddCertificate 和 ve dcdn CreateCertBind,可以高效地完成火山引擎全站加速的证书自动更新。关键点在于:

    • 证书中心是统一的,CDN 上传的证书可供 DCDN 使用
    • DCDN 的 DomainNames 必须精确匹配控制台中已添加的加速域名(不支持通配符形式的域名)
    • 不同命令的错误响应结构可能不同,需要编写健壮的解析逻辑

    上述脚本配合1Panel执行,即可在证书更新后自动部署,告别手动操作的烦恼。


    由 AI 生成

    本文著作权归作者 [ HORiZON ] 享有,未经作者书面授权,禁止转载,封面图片来源于 [ 互联网 ] ,本文仅供个人学习、研究和欣赏使用。如有异议,请联系博主及时处理。
    AIGC
    Linux
    — END —
    首页归档
    由 Typecho 驱动  已运行 2173 天
    豫ICP备2022003436号-1
    OneBlog   0.110 s
    深色
    OneBlog主题  Load 0.110 sCopyRight © 2026 HORiZON. All Rights Reserved

    开源不易,请尊重作者版权,保留基本的版权信息。