Update ssl
This commit is contained in:
245
ssl
245
ssl
@@ -1,202 +1,75 @@
|
|||||||
cat >/usr/local/bin/issue_cert.sh <<'EOF'
|
cat << 'EOF' > cert_apply.sh
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
# POSIX sh script: compatible with Debian/Ubuntu/Alpine/busybox
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
INSTALL_BASE="/data"
|
# --- 1. 获取用户输入 ---
|
||||||
KEY_NAME="key.pem"
|
read -p "请输入您要申请的域名 (例如: ui.shanghi.net): " DOMAIN
|
||||||
FULLCHAIN_NAME="fullchain.pem"
|
|
||||||
CA_SERVER="letsencrypt"
|
|
||||||
DEBUG_LEVEL="${DEBUG_LEVEL:-0}" # 0=off, 1=--debug, 2=--debug 2
|
|
||||||
ACME_SH="${ACME_SH:-}" # allow override: ACME_SH=/path/to/acme.sh issue_cert.sh xxx
|
|
||||||
|
|
||||||
log() { printf '\n[%s] %s\n' "$(date '+%F %T')" "$*"; }
|
# 简单的非空检查
|
||||||
err() { printf '\n[ERROR] %s\n' "$*" >&2; }
|
if [ -z "$DOMAIN" ]; then
|
||||||
|
echo "错误:域名不能为空!"
|
||||||
usage() {
|
exit 1
|
||||||
cat <<USAGE
|
|
||||||
用法:
|
|
||||||
issue_cert.sh <domain> [--email you@example.com] [--force] [--wildcard]
|
|
||||||
|
|
||||||
说明:
|
|
||||||
1) 优先 Cloudflare DNS API(检测到 CF_Token 时自动启用,支持自动续期)
|
|
||||||
2) 再尝试 standalone 80(需要公网80可达,支持自动续期但续期仍需80)
|
|
||||||
3) 最后保底手动 DNS(可签发但无法自动续期)
|
|
||||||
|
|
||||||
输出:
|
|
||||||
/data/<domain>/key.pem
|
|
||||||
/data/<domain>/fullchain.pem
|
|
||||||
|
|
||||||
可选环境变量:
|
|
||||||
ACME_SH=/root/.acme.sh/acme.sh # 指定 acme.sh 路径
|
|
||||||
DEBUG_LEVEL=1 或 2 # 打开调试输出(对应 acme.sh --debug 或 --debug 2)
|
|
||||||
|
|
||||||
示例:
|
|
||||||
issue_cert.sh ui.shanghi.net
|
|
||||||
CF_Token=xxx issue_cert.sh ui.shanghi.net
|
|
||||||
DEBUG_LEVEL=2 issue_cert.sh ui.shanghi.net --force
|
|
||||||
USAGE
|
|
||||||
}
|
|
||||||
|
|
||||||
# ---- parse args ----
|
|
||||||
[ $# -ge 1 ] || { usage; exit 1; }
|
|
||||||
DOMAIN="$1"; shift
|
|
||||||
|
|
||||||
EMAIL=""
|
|
||||||
FORCE="0"
|
|
||||||
WILDCARD="0"
|
|
||||||
|
|
||||||
while [ $# -gt 0 ]; do
|
|
||||||
case "$1" in
|
|
||||||
--email) EMAIL="${2:-}"; [ -n "$EMAIL" ] || { err "--email 缺少参数"; exit 1; }; shift 2;;
|
|
||||||
--force) FORCE="1"; shift;;
|
|
||||||
--wildcard) WILDCARD="1"; shift;;
|
|
||||||
-h|--help) usage; exit 0;;
|
|
||||||
*) err "未知参数: $1"; usage; exit 1;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# ---- find acme.sh ----
|
|
||||||
find_acme() {
|
|
||||||
if [ -n "${ACME_SH}" ] && [ -x "${ACME_SH}" ]; then
|
|
||||||
echo "${ACME_SH}"; return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Common locations
|
|
||||||
if [ -x "$HOME/.acme.sh/acme.sh" ]; then echo "$HOME/.acme.sh/acme.sh"; return 0; fi
|
|
||||||
if [ -x "/root/.acme.sh/acme.sh" ]; then echo "/root/.acme.sh/acme.sh"; return 0; fi
|
|
||||||
|
|
||||||
# Try to locate in PATH
|
|
||||||
if command -v acme.sh >/dev/null 2>&1; then
|
|
||||||
command -v acme.sh; return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
ACME="$(find_acme || true)"
|
|
||||||
|
|
||||||
# ---- install acme.sh if missing ----
|
|
||||||
if [ -z "$ACME" ]; then
|
|
||||||
log "未发现 acme.sh,开始安装..."
|
|
||||||
if ! command -v curl >/dev/null 2>&1; then
|
|
||||||
err "系统没有 curl,请先安装 curl。"; exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$EMAIL" ]; then
|
|
||||||
curl -fsSL https://get.acme.sh | sh -s email="$EMAIL"
|
|
||||||
else
|
|
||||||
curl -fsSL https://get.acme.sh | sh
|
|
||||||
fi
|
|
||||||
|
|
||||||
ACME="$(find_acme || true)"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ -n "$ACME" ] || { err "仍未找到 acme.sh。请确认安装用户与执行用户一致,或用 ACME_SH 指定路径。"; exit 1; }
|
# 确认信息
|
||||||
|
echo "----------------------------------------"
|
||||||
|
echo "准备为域名: $DOMAIN 申请证书"
|
||||||
|
echo "存放路径: /data/$DOMAIN.key"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
read -p "确认无误请按回车继续,取消请按 Ctrl+C ..."
|
||||||
|
|
||||||
log "使用 acme.sh: $ACME"
|
# --- 2. 基础配置 ---
|
||||||
|
CERT_BASE_DIR="/data"
|
||||||
|
EMAIL="my@example.com" # 默认邮箱,不需要每次改
|
||||||
|
|
||||||
# ---- prepare debug flags ----
|
# 确保目录存在
|
||||||
DBG=""
|
mkdir -p $CERT_BASE_DIR
|
||||||
if [ "$DEBUG_LEVEL" = "1" ]; then DBG="--debug"; fi
|
|
||||||
if [ "$DEBUG_LEVEL" = "2" ]; then DBG="--debug 2"; fi
|
|
||||||
|
|
||||||
# ---- set CA ----
|
# --- 3. 环境检查 (安装 socat) ---
|
||||||
log "设置默认 CA 为: $CA_SERVER"
|
# 只有未安装时才尝试安装
|
||||||
# shellcheck disable=SC2086
|
if ! command -v socat &> /dev/null; then
|
||||||
$ACME --set-default-ca --server "$CA_SERVER" $DBG >/dev/null 2>&1 || true
|
echo "正在安装 socat (Standalone模式依赖)..."
|
||||||
|
if [ -f /usr/bin/apt ]; then
|
||||||
# ---- prepare install dir ----
|
apt update && apt install socat -y
|
||||||
INSTALL_DIR="${INSTALL_BASE}/${DOMAIN}"
|
elif [ -f /usr/bin/yum ]; then
|
||||||
mkdir -p "$INSTALL_DIR"
|
yum install socat -y
|
||||||
|
|
||||||
KEY_PATH="${INSTALL_DIR}/${KEY_NAME}"
|
|
||||||
FULLCHAIN_PATH="${INSTALL_DIR}/${FULLCHAIN_NAME}"
|
|
||||||
|
|
||||||
# ---- build issue args ----
|
|
||||||
ISSUE_DOMAINS="-d $DOMAIN"
|
|
||||||
if [ "$WILDCARD" = "1" ]; then
|
|
||||||
# 注意:通配符只适用于 DNS 验证。并且对 ui.shanghi.net 这样的子域,
|
|
||||||
# 通配符 *.ui.shanghi.net 通常没意义。一般通配符用于 shanghi.net -> *.shanghi.net
|
|
||||||
ISSUE_DOMAINS="-d $DOMAIN -d *.$DOMAIN"
|
|
||||||
fi
|
|
||||||
|
|
||||||
FORCE_FLAG=""
|
|
||||||
[ "$FORCE" = "1" ] && FORCE_FLAG="--force"
|
|
||||||
|
|
||||||
install_cert() {
|
|
||||||
log "安装证书到: $INSTALL_DIR"
|
|
||||||
# shellcheck disable=SC2086
|
|
||||||
$ACME --install-cert -d "$DOMAIN" \
|
|
||||||
--key-file "$KEY_PATH" \
|
|
||||||
--fullchain-file "$FULLCHAIN_PATH" \
|
|
||||||
--reloadcmd "echo cert_installed_for_$DOMAIN" $DBG
|
|
||||||
|
|
||||||
log "证书文件已生成:"
|
|
||||||
ls -l "$KEY_PATH" "$FULLCHAIN_PATH" 2>/dev/null || true
|
|
||||||
|
|
||||||
if command -v openssl >/dev/null 2>&1; then
|
|
||||||
log "证书信息:"
|
|
||||||
openssl x509 -in "$FULLCHAIN_PATH" -noout -subject -issuer -dates 2>/dev/null || true
|
|
||||||
fi
|
fi
|
||||||
}
|
else
|
||||||
|
echo "检测到 socat 已安装,跳过安装步骤。"
|
||||||
|
fi
|
||||||
|
|
||||||
try_cf_dns() {
|
# --- 4. 核心申请逻辑 ---
|
||||||
if [ -n "${CF_Token:-}" ]; then
|
# 检查 80 端口是否被占用 (简单的防呆检查)
|
||||||
log "检测到 CF_Token,尝试 Cloudflare DNS API(dns_cf)..."
|
if lsof -Pi :80 -sTCP:LISTEN -t >/dev/null ; then
|
||||||
# shellcheck disable=SC2086
|
echo "警告:检测到 80 端口被占用!"
|
||||||
$ACME --issue $ISSUE_DOMAINS --dns dns_cf $FORCE_FLAG $DBG && return 0
|
echo "Standalone 模式需要占用 80 端口。请先停止 Nginx/Apache,或确保没有服务占用 80。"
|
||||||
log "Cloudflare DNS API 失败,继续尝试其他方式。"
|
read -p "是否强制尝试继续? (y/n): " force_run
|
||||||
|
if [ "$force_run" != "y" ]; then
|
||||||
|
echo "脚本已终止。"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
try_standalone() {
|
|
||||||
if [ "$WILDCARD" = "1" ]; then
|
|
||||||
log "通配符不支持 standalone 80,跳过。"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "尝试 standalone 80(需要公网80可达,且本机可绑定80)..."
|
|
||||||
# shellcheck disable=SC2086
|
|
||||||
$ACME --issue $ISSUE_DOMAINS --standalone $FORCE_FLAG $DBG && return 0
|
|
||||||
log "standalone 80 失败。"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
try_manual_dns() {
|
|
||||||
log "进入保底:手动 DNS TXT 验证(--dns)。"
|
|
||||||
log "提示:手动 DNS 无法自动续期(续期仍需手动加 TXT)。"
|
|
||||||
# shellcheck disable=SC2086
|
|
||||||
$ACME --issue $ISSUE_DOMAINS --dns $FORCE_FLAG $DBG || return 1
|
|
||||||
|
|
||||||
log "上面已输出 TXT 记录,请去 DNS 面板添加,等待生效后再执行:"
|
|
||||||
echo " $ACME --renew -d $DOMAIN --force $DBG"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
log "开始签发:$DOMAIN"
|
|
||||||
log "输出目录:$INSTALL_DIR"
|
|
||||||
|
|
||||||
if try_cf_dns; then
|
|
||||||
install_cert
|
|
||||||
log "完成:DNS API 模式支持自动续期(acme.sh 自带 cronjob 管理)。"
|
|
||||||
exit 0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if try_standalone; then
|
echo "正在向 CA 机构申请证书..."
|
||||||
install_cert
|
~/.acme.sh/acme.sh --issue -d "$DOMAIN" --standalone --email "$EMAIL" --force \
|
||||||
log "完成:standalone 模式支持自动续期,但续期时仍需要 80 可用且公网可达。"
|
--install-cert -d "$DOMAIN" \
|
||||||
exit 0
|
--key-file "$CERT_BASE_DIR/$DOMAIN.key" \
|
||||||
fi
|
--fullchain-file "$CERT_BASE_DIR/$DOMAIN.crt" \
|
||||||
|
--reloadcmd "echo \"\$(date): 证书 $DOMAIN 已更新\" >> /var/log/acme_renewal.log"
|
||||||
|
|
||||||
if try_manual_dns; then
|
# --- 5. 结果反馈 ---
|
||||||
log "已进入手动 DNS 模式:按提示添加 TXT 后续期/完成。"
|
if [ $? -eq 0 ]; then
|
||||||
exit 0
|
echo ""
|
||||||
|
echo "========================================================"
|
||||||
|
echo " ✅ 证书申请成功!"
|
||||||
|
echo " 域名: $DOMAIN"
|
||||||
|
echo " 公钥 (crt): $CERT_BASE_DIR/$DOMAIN.crt"
|
||||||
|
echo " 私钥 (key): $CERT_BASE_DIR/$DOMAIN.key"
|
||||||
|
echo "========================================================"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
echo " ❌ 申请失败。"
|
||||||
|
echo "请检查:1. 域名解析是否生效? 2. 防火墙是否放行了 80 端口?"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
err "全部方式失败。建议:DEBUG_LEVEL=2 issue_cert.sh $DOMAIN --force 观察详细日志。"
|
|
||||||
exit 1
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
chmod +x /usr/local/bin/issue_cert.sh
|
chmod +x cert_apply.sh
|
||||||
|
|||||||
Reference in New Issue
Block a user