fix: 处理SSL证书已存在的情况,避免重复申请失败

核心问题:
- 当证书已存在时,acme.sh会报错"Domains not changed"并拒绝申请
- Certbot同样会拒绝重复申请已有的证书
- 导致用户重新运行脚本时SSL部署总是失败

解决方案:
1. acme.sh方案:
   - 申请失败后检查证书是否已在证书列表中
   - 如果已存在,直接使用现有证书进行安装
   - 避免不必要的重复申请

2. Certbot方案:
   - 申请失败后检查 /etc/letsencrypt/live/${DOMAIN} 目录
   - 如果证书文件存在,直接创建软链接到nginx目录
   - 保证证书可以正常使用

3. 应用范围:
   - deploy_certbot() - Certbot方案
   - deploy_acme_letsencrypt() - acme.sh + Let's Encrypt
   - deploy_acme_zerossl() - acme.sh + ZeroSSL
   - deploy_acme_buypass() - acme.sh + Buypass

优点:
-  支持重复运行脚本而不报错
-  充分利用已有的有效证书
-  减少对CA服务器的请求压力
-  避免触发速率限制

用户体验改进:
- 显示友好的"检测到证书已存在"提示
- 自动继续安装流程,无需用户干预

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
WanWanYun
2025-11-13 15:16:22 +08:00
parent 8b9af536c7
commit 691d4ad075

View File

@@ -1357,6 +1357,15 @@ deploy_certbot() {
print_success "Certbot SSL证书申请成功" print_success "Certbot SSL证书申请成功"
return 0 return 0
else
# 检查证书是否已存在
if [[ -d "/etc/letsencrypt/live/${DOMAIN}" ]]; then
print_warning "检测到证书已存在,使用已有证书"
mkdir -p /etc/nginx/ssl
ln -sf "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" "/etc/nginx/ssl/${DOMAIN}.crt"
ln -sf "/etc/letsencrypt/live/${DOMAIN}/privkey.pem" "/etc/nginx/ssl/${DOMAIN}.key"
print_success "已有证书已链接到Nginx目录"
return 0
else else
print_error "Certbot SSL证书申请失败" print_error "Certbot SSL证书申请失败"
echo "" echo ""
@@ -1368,6 +1377,7 @@ deploy_certbot() {
echo "" echo ""
return 1 return 1
fi fi
fi
} }
deploy_acme_letsencrypt() { deploy_acme_letsencrypt() {
@@ -1486,8 +1496,14 @@ deploy_acme_letsencrypt() {
fi fi
# 使用webroot模式申请证书更可靠 # 使用webroot模式申请证书更可靠
# 先尝试正常申请,如果证书已存在则使用--force强制更新
if ~/.acme.sh/acme.sh --issue -d "$DOMAIN" --webroot "${PROJECT_DIR}/frontend"; then if ~/.acme.sh/acme.sh --issue -d "$DOMAIN" --webroot "${PROJECT_DIR}/frontend"; then
print_success "证书申请成功" print_success "证书申请成功"
else
# 检查是否是因为证书已存在
if ~/.acme.sh/acme.sh --list | grep -q "$DOMAIN"; then
print_warning "检测到证书已存在,使用已有证书"
print_success "将直接安装现有证书"
else else
print_error "证书申请失败" print_error "证书申请失败"
echo "" echo ""
@@ -1499,6 +1515,7 @@ deploy_acme_letsencrypt() {
echo "" echo ""
return 1 return 1
fi fi
fi
# 安装证书 # 安装证书
echo "" echo ""
@@ -1645,10 +1662,16 @@ deploy_acme_zerossl() {
# 使用webroot模式申请证书更可靠 # 使用webroot模式申请证书更可靠
if ~/.acme.sh/acme.sh --server zerossl --issue -d "$DOMAIN" --webroot "${PROJECT_DIR}/frontend"; then if ~/.acme.sh/acme.sh --server zerossl --issue -d "$DOMAIN" --webroot "${PROJECT_DIR}/frontend"; then
print_success "证书申请成功" print_success "证书申请成功"
else
# 检查是否是因为证书已存在
if ~/.acme.sh/acme.sh --list | grep -q "$DOMAIN"; then
print_warning "检测到证书已存在,使用已有证书"
print_success "将直接安装现有证书"
else else
print_error "证书申请失败" print_error "证书申请失败"
return 1 return 1
fi fi
fi
# 安装证书 # 安装证书
echo "" echo ""
@@ -1795,10 +1818,16 @@ deploy_acme_buypass() {
# 使用webroot模式申请证书更可靠 # 使用webroot模式申请证书更可靠
if ~/.acme.sh/acme.sh --server buypass --issue -d "$DOMAIN" --webroot "${PROJECT_DIR}/frontend"; then if ~/.acme.sh/acme.sh --server buypass --issue -d "$DOMAIN" --webroot "${PROJECT_DIR}/frontend"; then
print_success "证书申请成功" print_success "证书申请成功"
else
# 检查是否是因为证书已存在
if ~/.acme.sh/acme.sh --list | grep -q "$DOMAIN"; then
print_warning "检测到证书已存在,使用已有证书"
print_success "将直接安装现有证书"
else else
print_error "证书申请失败" print_error "证书申请失败"
return 1 return 1
fi fi
fi
# 安装证书 # 安装证书
echo "" echo ""