Files
youlegames/codes/agent/game-docker/init-ssl.sh
2026-04-10 16:44:13 +08:00

195 lines
6.1 KiB
Bash
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.
#!/bin/bash
# ============================================
# SSL 证书初始化脚本(首次部署时运行)
#
# 使用 Let's Encrypt (certbot) 为 3 个域名申请证书
# 流程:
# 1. 启动 Nginx仅 HTTP 80 端口,用于 ACME 验证)
# 2. 用 certbot 对每个域名申请证书
# 3. 重新加载 Nginx 以启用 HTTPS
#
# 用法:
# ./init-ssl.sh # 正式申请证书
# ./init-ssl.sh --staging # 使用 staging 环境测试(不受速率限制)
# ./init-ssl.sh --dry-run # 仅测试,不真正申请
# ============================================
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$SCRIPT_DIR"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# 加载 .env
if [ ! -f .env ]; then
log_error ".env 文件不存在!请先执行: cp .env.example .env 并填写配置"
exit 1
fi
source .env
# 检查必要变量
if [ -z "$SSL_EMAIL" ]; then
log_error "请在 .env 中设置 SSL_EMAIL用于 Let's Encrypt 证书申请通知)"
exit 1
fi
if [ -z "$API_DOMAIN" ] || [ -z "$DLWEB_DOMAIN" ] || [ -z "$WX_DOMAIN" ]; then
log_error "请在 .env 中设置 API_DOMAIN, DLWEB_DOMAIN, WX_DOMAIN"
exit 1
fi
DOMAINS=("$API_DOMAIN" "$DLWEB_DOMAIN" "$WX_DOMAIN")
# 判断使用 docker-compose 还是 docker compose
COMPOSE_CMD="docker compose"
if ! docker compose version &> /dev/null 2>&1; then
COMPOSE_CMD="docker-compose"
fi
# 解析参数
STAGING_ARG=""
DRY_RUN=""
for arg in "$@"; do
case $arg in
--staging)
STAGING_ARG="--staging"
log_warn "使用 Let's Encrypt Staging 环境(测试用,证书不受信任)"
;;
--dry-run)
DRY_RUN="--dry-run"
log_warn "Dry-run 模式,不会真正申请证书"
;;
esac
done
# ============================================
# Step 1: 生成临时自签名证书(让 Nginx 能先启动)
# ============================================
log_info "Step 1: 生成临时自签名证书..."
for domain in "${DOMAINS[@]}"; do
CERT_DIR="./docker/nginx/dummy-certs/$domain"
mkdir -p "$CERT_DIR"
if [ ! -f "$CERT_DIR/fullchain.pem" ]; then
openssl req -x509 -nodes -newkey rsa:2048 -days 1 \
-keyout "$CERT_DIR/privkey.pem" \
-out "$CERT_DIR/fullchain.pem" \
-subj "/CN=$domain" 2>/dev/null
log_info " 已生成临时自签名证书: $domain"
fi
done
# ============================================
# Step 2: 将临时证书复制到 certbot volume
# ============================================
log_info "Step 2: 初始化证书 volume..."
# 确保容器和 volume 存在
$COMPOSE_CMD up -d nginx 2>/dev/null || true
# 将临时证书复制到 certbot-certs volume
for domain in "${DOMAINS[@]}"; do
CERT_DIR="./docker/nginx/dummy-certs/$domain"
LIVE_DIR="/etc/letsencrypt/live/$domain"
# 通过 nginx 容器操作 volume
docker exec youle-nginx sh -c "mkdir -p $LIVE_DIR" 2>/dev/null || true
docker cp "$CERT_DIR/fullchain.pem" "youle-nginx:$LIVE_DIR/fullchain.pem"
docker cp "$CERT_DIR/privkey.pem" "youle-nginx:$LIVE_DIR/privkey.pem"
done
# 重新加载 Nginx 以使用临时证书
docker exec youle-nginx nginx -s reload 2>/dev/null || true
log_info " Nginx 已使用临时证书启动"
# ============================================
# Step 3: 用 certbot 申请真实证书
# ============================================
log_info "Step 3: 申请 Let's Encrypt 证书..."
for domain in "${DOMAINS[@]}"; do
log_info " 正在为 $domain 申请证书..."
$COMPOSE_CMD run --rm certbot certonly \
--webroot \
-w /var/www/certbot \
--email "$SSL_EMAIL" \
--agree-tos \
--no-eff-email \
--force-renewal \
-d "$domain" \
$STAGING_ARG \
$DRY_RUN
if [ $? -eq 0 ]; then
log_info "$domain 证书申请成功"
else
log_error "$domain 证书申请失败!请检查:"
log_error " - 域名 DNS 是否已正确解析到本服务器"
log_error " - 服务器 80 端口是否对外开放"
log_error " - 是否超过 Let's Encrypt 速率限制(可用 --staging 测试)"
fi
done
# ============================================
# Step 4: 重新加载 Nginx 以使用真实证书
# ============================================
log_info "Step 4: 重新加载 Nginx..."
docker exec youle-nginx nginx -s reload
# ============================================
# Step 5: 清理临时文件并启动 certbot 定时续签
# ============================================
rm -rf ./docker/nginx/dummy-certs
log_info "Step 5: 启动 certbot 自动续签服务..."
$COMPOSE_CMD up -d certbot
# ============================================
# Step 6: 安装 crontab 定时重载 Nginx使续签生效
# ============================================
log_info "Step 6: 设置自动重载 Nginx 的 crontab..."
CRON_JOB="0 */12 * * * docker exec youle-nginx nginx -s reload >/dev/null 2>&1"
CRON_MARKER="# youle-nginx-ssl-reload"
# 检查是否已存在
if crontab -l 2>/dev/null | grep -q "$CRON_MARKER"; then
log_info " crontab 已存在,跳过"
else
# 追加到当前用户的 crontab
(crontab -l 2>/dev/null; echo "$CRON_JOB $CRON_MARKER") | crontab -
log_info " 已添加 crontab: 每 12 小时重载 Nginx使续签的证书生效"
fi
echo ""
log_info "============================================"
log_info "SSL 初始化完成!"
log_info "============================================"
echo ""
echo " 证书信息:"
for domain in "${DOMAINS[@]}"; do
echo " https://$domain"
done
echo ""
echo " 证书有效期: 90 天"
echo " 自动续签: certbot 容器每 12 小时检查一次"
echo " 自动重载: crontab 每 12 小时执行 nginx -s reload"
echo ""
echo " 查看证书状态:"
echo " $COMPOSE_CMD run --rm certbot certificates"
echo ""
echo " 手动续签:"
echo " ./deploy.sh ssl-renew"
echo ""