腾讯云SSL证书自动更新

发布于 2025年5月16日

本文内容由AI生成并经过人工精选,不保证100%准确,请酌情参考使用

SSL证书

完整脚本如下:

#!/bin/bash
set -euo pipefail

# 配置信息
Domains=("")  # 域名列表
CertBaseDir="/usr/local/nginx/cert"  # 证书存储目录
TempDir="/usr/local/nginx/tmp"        # 临时目录
DaysBeforeExpire=7            # 到期前7天更新
NginxBin="/usr/local/nginx/sbin/nginx"  # Nginx二进制路径

# 创建临时目录
mkdir -p "$TempDir"

# 函数:输出错误并退出当前域名处理流程
error_exit() {
  echo "[错误] $1" >&2
  exit 1  # 终止当前子流程
}

# 函数:从域名中提取主机记录
get_host_record() {
  local domain="$1"
  echo "$domain" | awk -F'.' '{print $1}'
}

# 函数:检查证书过期时间
check_cert_expiry() {
  local domain="$1"
  local host_record=$(get_host_record "$domain")
  local cert_file="$CertBaseDir/${host_record}.pem"
  
  if [ ! -f "$cert_file" ]; then
    echo "证书文件不存在,触发新证书申请。"
    return 0
  fi

  local expire_date expire_timestamp current_timestamp seconds_left days_left
  expire_date=$(openssl x509 -enddate -noout -in "$cert_file" 2>/dev/null) || error_exit "无法读取证书有效期"
  expire_date=${expire_date#*=}
  expire_timestamp=$(date -d "$expire_date" +%s 2>/dev/null) || error_exit "日期转换失败"
  current_timestamp=$(date +%s)
  seconds_left=$((expire_timestamp - current_timestamp))
  days_left=$((seconds_left / 86400))

  [ $days_left -le $DaysBeforeExpire ] && return 0 || return 1
}

# 函数:处理单个域名更新流程
process_domain() {
  local domain="$1"
  local host_record=$(get_host_record "$domain")
  echo "===== 开始处理域名: $domain (主机记录: $host_record) ====="

  # 申请证书(使用DNS_AUTO自动验证)
  echo "申请新证书(DNS自动验证)..."
  cert_response=$(tccli ssl ApplyCertificate \
    --DomainName "$domain" \
    --DvAuthMethod DNS_AUTO 2>&1) || error_exit "证书申请失败:$cert_response"
  cert_id=$(jq -r '.CertificateId' <<< "$cert_response") || error_exit "无法解析证书ID"

  # 等待证书签发(最多等待10分钟)
  echo "等待证书签发..."
  local status
  for _ in {1..20}; do
    status_response=$(tccli ssl DescribeCertificate \
      --CertificateId "$cert_id" 2>&1) || error_exit "证书状态查询失败:$status_response"
    status=$(jq -r '.StatusName' <<< "$status_response")
    [ "$status" = "已颁发" ] && break
    echo "下一轮尝试"
    sleep 30
  done
  [ "$status" = "已颁发" ] || error_exit "证书签发超时(最终状态:$status)"

  # 下载证书(处理Base64内容)
  echo "下载证书..."
  download_response=$(tccli ssl DownloadCertificate \
    --CertificateId "$cert_id" 2>&1) || error_exit "证书下载失败:$download_response"
  
  # 提取Base64内容并解码为ZIP文件
  echo "解码证书文件..."
  zip_file="$TempDir/$domain.zip"
  content=$(jq -r '.Content' <<< "$download_response") || error_exit "无法解析证书内容"
  echo "$content" | base64 -d > "$zip_file" || error_exit "Base64解码失败"
  [ -s "$zip_file" ] || error_exit "生成的ZIP文件为空"  # 检查文件是否有效

  # 解压证书
  echo "解压证书..."
  unzip -oq "$zip_file" -d "$TempDir/$domain" 2>&1 || error_exit "解压失败"

  # 部署证书
  echo "部署证书..."
  mkdir -p "$CertBaseDir" || error_exit "无法创建证书目录"
  \cp -f "$TempDir/$domain/$domain.pem" "$CertBaseDir/${host_record}.pem" || error_exit "证书复制失败"
  \cp -f "$TempDir/$domain/$domain.key" "$CertBaseDir/${host_record}.key" || error_exit "私钥复制失败"

  # 清理临时文件
  echo "清理临时文件..."
  rm -rf "$TempDir/$domain.zip" "$TempDir/$domain" || error_exit "临时文件清理失败"

  # 检查Nginx配置并重载
  echo "执行Nginx配置测试..."
  nginx_test_output=$($NginxBin -t 2>&1)  # 捕获标准输出和错误
  echo "$nginx_test_output"  # 打印测试结果
  if echo "$nginx_test_output" | grep -q "successful"; then
    echo "配置验证通过,执行重载..."
    $NginxBin -s reload || error_exit "Nginx重载失败"
  else
    error_exit "Nginx配置测试失败,跳过重载"  # 终止当前域名流程,但不影响其他域名
  fi
}

# 主流程:逐个处理域名
for domain in "${Domains[@]}"; do
  (
    if check_cert_expiry "$domain"; then
      process_domain "$domain"
      echo "===== 域名 $domain 更新成功 ====="
    else
      echo "===== 域名 $domain 无需更新 ====="
    fi
  ) || echo "===== 域名 $domain 更新失败 ====="  # 错误已在前序流程中输出
done

echo "所有域名处理完成!"
腾讯云SSL证书自动更新