Files
acme-auto/backend/templates_cert/deploy-cert.sh.j2
T
2026-07-21 11:02:26 +08:00

90 lines
3.3 KiB
Django/Jinja
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -euo pipefail
# 补全 PATHcron 等非交互式环境默认 PATH 不含 /usr/sbin 等目录)
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PATH}"
# === 由 CertCenter 生成 ===
DOMAIN="{{ domain }}"
BASE_URL="{{ base_url }}"
TOKEN="{{ token }}"
CERT_DIR="{{ cert_dir }}"
CHECK_CMD="{{ check_cmd }}"
RELOAD_CMD="{{ reload_cmd }}"
CONFIG_ID="{{ acme_config_id }}"
# ===========================
CONFIG_PARAM=""
[[ -n "${CONFIG_ID}" ]] && CONFIG_PARAM="&acme_config_id=${CONFIG_ID}"
VERSION_URL="${BASE_URL}/api/version?domain=${DOMAIN}${CONFIG_PARAM}"
FULLCHAIN_URL="${BASE_URL}/api/cert/fullchain?domain=${DOMAIN}${CONFIG_PARAM}"
PRIVATE_URL="${BASE_URL}/api/cert/private?domain=${DOMAIN}${CONFIG_PARAM}"
TMP_DIR="/tmp/cert-sync-${DOMAIN//\*/_}"
VERSION_FILE="${CERT_DIR}/.version"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
mkdir -p "${CERT_DIR}" "${TMP_DIR}"
auth=(-H "Authorization: Bearer ${TOKEN}")
# -k 跳过 TLS 证书验证(CertCenter 初期可能使用自签证书)
# -S 显示错误信息(配合 -s 不显示进度条)
curl_opts=(-SfsSL -k --connect-timeout 5 --max-time 30)
log "开始同步证书: ${DOMAIN}"
log "配置目录: ${CERT_DIR}, 配置ID: ${CONFIG_ID:-无}"
# 1. 检查版本
log "检查远程版本..."
REMOTE=$(curl "${curl_opts[@]}" --max-time 15 "${auth[@]}" "${VERSION_URL}") || {
log "错误: 无法获取远程版本 (${VERSION_URL})"
exit 1
}
LOCAL=$(cat "${VERSION_FILE}" 2>/dev/null || echo "0")
log "远程版本: ${REMOTE}, 本地版本: ${LOCAL}"
if [[ "${REMOTE}" == "${LOCAL}" ]]; then
log "版本一致,跳过更新"
exit 0
fi
# 2. 下载证书
log "版本不一致,开始下载证书..."
curl "${curl_opts[@]}" "${auth[@]}" "${FULLCHAIN_URL}" -o "${TMP_DIR}/fullchain.pem" || {
log "错误: 下载 fullchain.pem 失败"
exit 1
}
curl "${curl_opts[@]}" "${auth[@]}" "${PRIVATE_URL}" -o "${TMP_DIR}/private.key" || {
log "错误: 下载 private.key 失败"
exit 1
}
chmod 600 "${TMP_DIR}/private.key"
log "证书下载完成"
# 3. 备份旧证书
cp -f "${CERT_DIR}/fullchain.pem" "${CERT_DIR}/fullchain.pem.bak" 2>/dev/null || true
cp -f "${CERT_DIR}/private.key" "${CERT_DIR}/private.key.bak" 2>/dev/null || true
log "旧证书已备份"
# 4. 原子替换
mv -f "${TMP_DIR}/fullchain.pem" "${CERT_DIR}/fullchain.pem"
mv -f "${TMP_DIR}/private.key" "${CERT_DIR}/private.key"
log "证书文件已替换"
# 5. 校验 & 重载 & 上报
HOSTNAME=$(hostname)
log "执行校验命令: ${CHECK_CMD}"
if ${CHECK_CMD}; then
log "校验通过,执行重载: ${RELOAD_CMD}"
echo "${REMOTE}" > "${VERSION_FILE}"
${RELOAD_CMD}
log "更新成功: ${DOMAIN} -> v${REMOTE}"
curl "${curl_opts[@]}" "${auth[@]}" -X POST "${BASE_URL}/api/report?domain=${DOMAIN}&status=success&hostname=${HOSTNAME}&message=deployed+v${REMOTE}${CONFIG_PARAM}" 2>/dev/null || true
else
log "错误: 校验失败,回滚证书"
mv -f "${CERT_DIR}/fullchain.pem.bak" "${CERT_DIR}/fullchain.pem" 2>/dev/null || true
mv -f "${CERT_DIR}/private.key.bak" "${CERT_DIR}/private.key" 2>/dev/null || true
log "已回滚到旧证书"
curl "${curl_opts[@]}" "${auth[@]}" -X POST "${BASE_URL}/api/report?domain=${DOMAIN}&status=failed&hostname=${HOSTNAME}&message=check+failed+rolled+back${CONFIG_PARAM}" 2>/dev/null || true
exit 1
fi