# OHTTPS 部署节点 (API)自动更新

在后台采用 nginx 进行前端网页部署,常常会需要进行证书的刷新,应为现在的证书一般最长不超过一年就需要进行更新替换,短的甚至一个月、90天就需要进行替换了,味了解决这个麻烦事,所以写下了这一个自动刷新证书的 bash 命令。

采用的方案是:

一个bash脚本,读取制定文件下的所有配置文件,再加上 crontab 修订添加定时任务。

# 1. BASH 命令内容

在这其中需要配置的就是配置文件的目录,修改 CONFIG_DIR 的值就可

#!/bin/bash
# 配置文件的目录
CONFIG_DIR="---"


# 遍历每个配置文件
for config_file in "$CONFIG_DIR"/*.conf; do
  echo "===== 开始处理配置文件:$config_file ====="

  # 读取配置文件内容
  source "$config_file"

  # 检查必填项
  if [[ -z "$apiId" || -z "$apiKey" || -z "$certificateId" || -z "$savePath" ]]; then
    echo "❌ 缺少必要参数,跳过 $config_file"
    continue
  fi

  # 设置默认值
  certName="${certName:-fullchain}"
  certKeyName="${certKeyName:-cert}"
  cycleDays="${cycleDays:-0}"
  expireThresholdDays="${expireThresholdDays:-15}"
  startDate="${startDate:-2025-06-10}"
  logName="${logName:-renew.log}"
  reloadCommand="${reloadCommand:-"nginx -s reload"}"

  mkdir -p "$savePath"
  LOG_FILE="${savePath}/${logName}"

  # 日志函数
  log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
  }

  log "📄 加载配置文件:$config_file"

  # 计算当前是第几天
  days_since_start=$(( ( $(date +%s) - $(date -d "$startDate" +%s) ) / 86400 ))

  # 缓存文件路径
  expireCacheFile="${savePath}/.cert_expired_time"

  # 默认不续签
  shouldRenew=false

  # 检查周期触发
  if (( cycleDays > 0 )) && (( days_since_start % cycleDays == 0 )); then
    log "📆 满足周期条件(每 $cycleDays 天,第 $days_since_start 天)"
    shouldRenew=true
  fi

  # 检查本地过期时间缓存
  if [ -f "$expireCacheFile" ]; then
    cached_expire_ts=$(date -d "$(cat "$expireCacheFile")" +%s)
    now_ts=$(date +%s)
    remain_days=$(( (cached_expire_ts - now_ts) / 86400 ))

    log "📁 本地缓存证书剩余有效天数:$remain_days 天"

    if (( remain_days <= expireThresholdDays )); then
      log "⚠️ 剩余天数 ≤ 阈值($expireThresholdDays),触发续签"
      shouldRenew=true
    fi
  else
    log "⚠️ 无缓存过期时间,默认尝试请求"
    shouldRenew=true
  fi

  # 不满足条件则跳过
  if [[ "$shouldRenew" != "true" ]]; then
    log "✅ 条件未满足,跳过续签"
    continue
  fi

  # 请求参数
  timestamp=$(date +%s%3N)
  stringForSign=$(echo -e "apiId=${apiId}\napiKey=${apiKey}\ncertificateId=${certificateId}\ntimestamp=${timestamp}" | sort | paste -sd '&')
  sign=$(echo -n "$stringForSign" | md5sum | awk '{print $1}')
  request_url="https://ohttps.com/api/open/getCertificate?apiId=${apiId}&certificateId=${certificateId}&timestamp=${timestamp}&sign=${sign}"

  log "🌐 请求证书信息..."
  response=$(curl -s "$request_url")

  success=$(echo "$response" | jq -r '.success')

  if [ "$success" = "true" ]; then
    certKey=$(echo "$response" | jq -r '.payload.certKey')
    fullChainCerts=$(echo "$response" | jq -r '.payload.fullChainCerts')
    expiredTime=$(echo "$response" | jq -r '.payload.expiredTime')

    # 保存文件
    echo "$certKey" > "${savePath}/${certKeyName}.key"
    echo "$fullChainCerts" > "${savePath}/${certName}.cer"
    echo "$expiredTime" > "$expireCacheFile"

    log "✅ 证书续签成功"
    log "🔒 私钥路径:${savePath}/${certKeyName}.key"
    log "📜 证书路径:${savePath}/${certName}.cer"
    log "📅 过期时间:$expiredTime"

    # 重载 Nginx 或其他服务
    log "🚀 执行 reload 命令:$reloadCommand"
    $reloadCommand &>> "$LOG_FILE"

    if [[ $? -eq 0 ]]; then
      log "🔁 服务重载成功"
    else
      log "❌ 服务重载失败,请检查日志"
    fi
  else
    msg=$(echo "$response" | jq -r '.msg')
    log "❌ 请求失败:$msg"
  fi

  echo "" >> "$LOG_FILE"
done

# 2. 配置文件的内容

配置文件字段

字段 内容 示例
domain 域名
apiId OHttps 证书部署节点ID
apiKey OHttps 证书部署密钥
certificateId OHttps 证书ID
certName 部署的证书节点名称, 会保存为 ${certName}.cer
certKeyName 部署的证书节点密钥, 会保存为 ${certKeyName}.key
savePath 部署证书的保存位置 eg. /etc/nginx/cert/www.example.com
startDate 开始日期,一般会从Ohttps 先获取该日期
cycleDays 循环周期,多久会刷新,或者过期
expireThresholdDays 失效时间阈值,会提前刷新

示例:

domain="www.example.com" 
apiId="push-xxxxx"
apiKey="xxxxxxxxxxxxxxxxxxxxxxx"
certificateId="cert-xxxxxxxxxx"
certName="fullchain"
certKeyName="cert"
savePath="/xxx/xxx/xxx"
startDate="2025-06-01"
cycleDays=39
expireThresholdDays=15

注意事项

设置这个循环周期只是为了减少这个API接口的调用,因为本人发现每调用一次api就会扣除 OHTTPS 中的余额