This commit is contained in:
jeremygan2021
2026-03-22 23:48:40 +08:00
parent c26c04cf44
commit 0037224648

View File

@@ -226,6 +226,89 @@ backup_old_configs() {
fi
}
# 清理所有可能冲突的 nginx 配置
cleanup_nginx_conflicts() {
log_step "清理 nginx 配置冲突..."
local cleaned=0
# 1. 清理所有包含此域名的配置文件
log_info "搜索包含 ${DOMAIN} 的配置文件..."
local conflict_files=$(grep -rl "server_name.*${DOMAIN}" /etc/nginx/ 2>/dev/null | grep -v ".bak-" | grep -v ".bak/")
if [[ -n "$conflict_files" ]]; then
echo "$conflict_files" | while read file; do
log_warn "发现冲突配置: $file"
# 检查是否有多个 server_name 指令
local count=$(grep -c "server_name" "$file" 2>/dev/null || echo 0)
if [[ $count -gt 1 ]]; then
# 如果文件中有多个域名,只移除此域名的配置
log_warn "文件包含多个域名,仅移除此域名的配置"
# 这比较复杂,暂时标记为需要手动处理
log_error "需要手动处理: $file"
elif [[ $count -eq 1 ]]; then
# 如果文件只有此域名,可以安全删除
local backup="${file}.bak-conflict-$(date +%s)"
mv "$file" "$backup"
log_info "已备份并移除冲突配置: $backup"
cleaned=$((cleaned + 1))
fi
done
fi
# 2. 清理 sites-enabled 中的符号链接
if [[ -L "${NGINX_ENABLED}/${DOMAIN}.conf" ]]; then
rm -f "${NGINX_ENABLED}/${DOMAIN}.conf"
log_info "已删除符号链接: ${NGINX_ENABLED}/${DOMAIN}.conf"
cleaned=$((cleaned + 1))
fi
# 3. 清理 sites-available 中的配置
if [[ -f "${NGINX_AVAILABLE}/${DOMAIN}.conf" ]]; then
rm -f "${NGINX_AVAILABLE}/${DOMAIN}.conf"
log_info "已删除配置: ${NGINX_AVAILABLE}/${DOMAIN}.conf"
cleaned=$((cleaned + 1))
fi
# 4. 清理 conf.d 中所有相关配置
local confd_files=$(find /etc/nginx/conf.d/ -name "*${DOMAIN}*.conf" -type f 2>/dev/null)
echo "$confd_files" | while read file; do
# 排除当前要生成的配置文件
if [[ "$file" != "$HTTPS_CONF_FILE" ]] && [[ "$file" != "$HTTP_CONF_FILE" ]]; then
local backup="${file}.bak-old-$(date +%s)"
mv "$file" "$backup"
log_info "已备份旧配置: $backup"
cleaned=$((cleaned + 1))
fi
done
# 5. 检查其他可能的配置位置
for dir in /etc/nginx/sites-enabled /etc/nginx/sites-available /etc/nginx/conf.d; do
if [[ -d "$dir" ]]; then
local other_files=$(find "$dir" -name "*.conf" -type f 2>/dev/null)
echo "$other_files" | while read file; do
if grep -q "server_name.*${DOMAIN}" "$file" 2>/dev/null; then
if [[ "$file" != "$HTTPS_CONF_FILE" ]] && [[ "$file" != "$HTTP_CONF_FILE" ]]; then
local backup="${file}.bak-extra-$(date +%s)"
mv "$file" "$backup"
log_warn "发现额外配置并已备份: $backup"
cleaned=$((cleaned + 1))
fi
fi
done
fi
done
if [[ $cleaned -eq 0 ]]; then
log_info "未发现配置冲突"
else
log_success "已清理 $cleaned 个冲突配置"
log_warn "建议运行: systemctl restart nginx"
fi
}
# 检查证书是否已存在且未过期
check_existing_certificate() {
log_step "检查现有证书..."
@@ -501,6 +584,87 @@ issue_certificate() {
fi
}
# 带重试的证书申请函数
issue_certificate_with_retry() {
local max_retries=3
local retry_count=0
local wait_seconds=5
while [[ $retry_count -lt $max_retries ]]; do
retry_count=$((retry_count + 1))
echo ""
log_step "尝试申请证书 (第 $retry_count/$max_retries 次)..."
# 调用基本的证书申请函数
if issue_certificate; then
log_success "✅ 证书申请成功!"
return 0
else
# 申请失败,分析原因
log_warn "⚠️ 第 $retry_count 次申请失败"
# 检查是否是配置问题导致的失败
if grep -q "Invalid response.*404" /var/log/provision-${DOMAIN}.log 2>/dev/null || grep -q "conflicting server name" /var/log/nginx/error.log 2>/dev/null; then
log_warn "检测到配置冲突问题,尝试清理并重试..."
# 再次清理配置
cleanup_nginx_conflicts
# 重新生成 HTTP 配置
generate_http_config
# 完全重启 nginx
log_info "重启 nginx 服务..."
if systemctl restart nginx >/dev/null 2>&1 || systemctl reload nginx >/dev/null 2>&1 || service nginx restart >/dev/null 2>&1; then
log_success "nginx 重启成功"
else
log_error "nginx 重启失败,请手动检查"
fi
# 等待一下让 nginx 完全启动
sleep $wait_seconds
fi
# 如果不是最后一次尝试,等待后重试
if [[ $retry_count -lt $max_retries ]]; then
echo ""
log_info "等待 ${wait_seconds} 秒后重试..."
sleep $wait_seconds
# 增加等待时间(指数退避)
wait_seconds=$((wait_seconds * 2))
fi
fi
done
# 所有重试都失败
log_error "❌ 经过 $max_retries 次尝试,证书申请仍然失败"
echo ""
log_error "可能的原因:"
echo " 1. 域名未正确解析到本服务器"
echo " 2. 防火墙阻止了 80 端口"
echo " 3. nginx 配置存在冲突"
echo " 4. webroot 目录权限不足"
echo ""
echo "建议的排查步骤:"
echo " # 1. 检查域名解析"
echo " dig ${DOMAIN}"
echo ""
echo " # 2. 测试 80 端口"
echo " curl -I http://${DOMAIN}/.well-known/acme-challenge/test"
echo ""
echo " # 3. 检查 nginx 配置"
echo " grep -r 'server_name.*${DOMAIN}' /etc/nginx/"
echo ""
echo " # 4. 检查 webroot 权限"
echo " ls -la ${WEBROOT}"
echo " sudo chown -R www-data:www-data ${WEBROOT}"
echo ""
return 1
}
# 安装证书到指定位置
install_certificate() {
log_step "安装证书到指定目录..."
@@ -796,6 +960,9 @@ main() {
install_acme_sh
setup_webroot
backup_old_configs
# 清理可能存在的 nginx 配置冲突
cleanup_nginx_conflicts
# 检查是否需要申请新证书
local skip_issue=false
@@ -806,12 +973,16 @@ main() {
fi
generate_http_config
# 在生成配置后再次清理冲突
cleanup_nginx_conflicts
reload_nginx
# 只有在需要申请新证书时才执行验证和申请流程
if [[ "$skip_issue" == "false" ]]; then
if check_domain_reachability; then
issue_certificate
issue_certificate_with_retry
else
log_error "域名可达性检测失败,无法继续"
exit 1