115 lines
4.3 KiB
Bash
115 lines
4.3 KiB
Bash
#!/bin/bash
|
||
# ============================================================
|
||
# 现有 VPS 证书过期 + 续期修复脚本
|
||
# 适用场景:用旧版 vless-ws-tls-setup.sh 部署的机器,
|
||
# 证书用 --standalone 申请,nginx 起来后一直占 80 端口,
|
||
# 导致 certbot renew 从第一次续期起就必定失败。
|
||
#
|
||
# 本脚本做的事:
|
||
# 1. 找到已部署的域名(从 /etc/letsencrypt/live 里找)
|
||
# 2. 用 certbot 的 nginx 插件重新签发证书(nginx 不需要停)
|
||
# 3. 把 renewal 配置里的 authenticator 改成 nginx 插件
|
||
# 4. 重写 cron 续期任务,加日志、用 deploy-hook
|
||
# 5. 跑一次 --dry-run 验证以后能不能正常自动续期
|
||
# ============================================================
|
||
|
||
set -e
|
||
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
CYAN='\033[0;36m'
|
||
NC='\033[0m'
|
||
|
||
info() { echo -e "${CYAN}[INFO]${NC} $1"; }
|
||
success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||
warning() { echo -e "${YELLOW}[!]${NC} $1"; }
|
||
error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
|
||
|
||
[ "$EUID" -ne 0 ] && error "请使用 root 用户运行"
|
||
|
||
# 1. 找域名
|
||
if [ -n "$1" ]; then
|
||
DOMAIN="$1"
|
||
else
|
||
DOMAIN=$(ls /etc/letsencrypt/live 2>/dev/null | grep -v README | head -1)
|
||
fi
|
||
[ -z "$DOMAIN" ] && error "找不到域名,请手动指定:bash $0 你的域名"
|
||
info "目标域名:$DOMAIN"
|
||
|
||
# 2. 确保 nginx 插件已安装
|
||
if ! dpkg -l | grep -q python3-certbot-nginx; then
|
||
info "安装 python3-certbot-nginx..."
|
||
apt-get update -qq && apt-get install -y -qq python3-certbot-nginx
|
||
fi
|
||
|
||
# 3. 检查 nginx 是否在跑(插件依赖 nginx 正常运行)
|
||
if ! systemctl is-active --quiet nginx; then
|
||
warning "nginx 当前未运行,先启动它"
|
||
systemctl start nginx || error "nginx 启动失败,请先手动修复 nginx 再运行本脚本"
|
||
fi
|
||
|
||
# 4. 用 nginx 插件强制重签证书(不停 nginx,不改端口占用)
|
||
info "用 nginx 插件重新签发证书(过程中不会中断现有连接)..."
|
||
EMAIL_GUESS=$(grep -oP '(?<=--email )\S+' /var/log/letsencrypt/letsencrypt.log 2>/dev/null | tail -1)
|
||
EMAIL_GUESS=${EMAIL_GUESS:-admin@${DOMAIN}}
|
||
|
||
certbot certonly --nginx \
|
||
--cert-name "$DOMAIN" \
|
||
-d "$DOMAIN" \
|
||
--non-interactive \
|
||
--agree-tos \
|
||
--email "$EMAIL_GUESS" \
|
||
--force-renewal \
|
||
|| error "证书重签失败,请检查:1. 域名解析是否指向本机 2. Cloudflare 是否切成灰色云朵(仅DNS)后再试"
|
||
|
||
success "证书重签成功"
|
||
|
||
# 5. 确认/修正 renewal 配置里的 authenticator
|
||
RENEWAL_CONF="/etc/letsencrypt/renewal/${DOMAIN}.conf"
|
||
if [ -f "$RENEWAL_CONF" ]; then
|
||
sed -i 's/^authenticator = .*/authenticator = nginx/' "$RENEWAL_CONF"
|
||
if grep -q '^installer = ' "$RENEWAL_CONF"; then
|
||
sed -i 's/^installer = .*/installer = nginx/' "$RENEWAL_CONF"
|
||
else
|
||
sed -i '/^\[renewalparams\]/a installer = nginx' "$RENEWAL_CONF"
|
||
fi
|
||
success "已确认 $RENEWAL_CONF 中 authenticator = nginx"
|
||
else
|
||
warning "未找到 $RENEWAL_CONF,续期方式可能没有正确记录,请手动检查"
|
||
fi
|
||
|
||
# 6. 重写 cron 续期任务
|
||
mkdir -p /var/log
|
||
touch /var/log/certbot-renew.log
|
||
|
||
cat > /etc/cron.d/certbot-renew << CRONEOF
|
||
# Let's Encrypt 证书自动续期 - 每周一凌晨3点执行
|
||
0 3 * * 1 root certbot renew --deploy-hook "systemctl reload nginx" >> /var/log/certbot-renew.log 2>&1
|
||
CRONEOF
|
||
chmod 644 /etc/cron.d/certbot-renew
|
||
systemctl restart cron
|
||
success "已重写 cron 续期任务,日志输出到 /var/log/certbot-renew.log"
|
||
|
||
# 7. 让 nginx 加载新证书
|
||
systemctl reload nginx
|
||
success "nginx 已重新加载新证书"
|
||
|
||
# 8. 验证以后能不能正常自动续期(这次 nginx 是开着的,应该会通过)
|
||
info "验证自动续期是否正常(dry-run,nginx 全程不会停)..."
|
||
if certbot renew --dry-run >> /var/log/certbot-renew.log 2>&1; then
|
||
success "续期验证通过!以后不会再出现到期后失效的问题"
|
||
else
|
||
warning "验证仍未通过,详情见 /var/log/certbot-renew.log,请贴出来我再帮你看"
|
||
fi
|
||
|
||
CERT_PATH="/etc/letsencrypt/live/${DOMAIN}/fullchain.pem"
|
||
if [ -f "$CERT_PATH" ]; then
|
||
CERT_EXPIRY=$(openssl x509 -enddate -noout -in "$CERT_PATH" | cut -d= -f2)
|
||
echo ""
|
||
success "当前证书有效期至:$CERT_EXPIRY"
|
||
fi
|
||
|
||
echo ""
|
||
info "以后排查续期问题直接看日志:cat /var/log/certbot-renew.log"
|