#!/usr/bin/env bash # ════════════════════════════════════════════════════════════════ # 光湖 · 服务器标准模板部署脚本 # 将任意腾讯云服务器初始化为铸渊主控节点 # ════════════════════════════════════════════════════════════════ # # 用法: # sudo bash bootstrap.sh --gitea-url https://guanghulab.com \ # --api-token \ # --runner-name # # 此脚本会: # 1. 更新系统 + 安装基础软件 (Node.js 20, PM2, Nginx, git, curl) # 2. 创建 /data/guanghulab/ 目录结构 # 3. 从 Gitea 克隆仓库 # 4. 安装 Gitea Actions Runner # 5. 启动 Secrets Vault (如当前是Gitea服务器则跳过) # 6. 上报完成状态 # # ════════════════════════════════════════════════════════════════ set -euo pipefail # ─── 配置 ───────────────────────────────────────────────────── GITEA_URL="" API_TOKEN="" RUNNER_NAME="" DATA_DIR="/data/guanghulab" LOG_DIR="${DATA_DIR}/logs" GITEA_OWNER="bingshuo" GITEA_REPO="guanghulab" # 颜色 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' NC='\033[0m' log_info() { echo -e "${GREEN}[✓]${NC} $*"; } log_step() { echo -e "${CYAN}[→]${NC} $*"; } log_error() { echo -e "${RED}[✗]${NC} $*"; } # ─── 解析参数 ───────────────────────────────────────────────── while [[ $# -gt 0 ]]; do case $1 in --gitea-url) GITEA_URL="$2"; shift 2 ;; --api-token) API_TOKEN="$2"; shift 2 ;; --runner-name) RUNNER_NAME="$2"; shift 2 ;; --data-dir) DATA_DIR="$2"; shift 2 ;; *) log_error "未知参数: $1"; exit 1 ;; esac done if [[ -z "$GITEA_URL" || -z "$API_TOKEN" ]]; then log_error "必须提供 --gitea-url 和 --api-token" exit 1 fi RUNNER_NAME="${RUNNER_NAME:-zhuyuan-runner-$(hostname | tr '[:upper:]' '[:lower:]')}" echo -e "${CYAN}═══════════════════════════════════════════════════════${NC}" echo -e "${CYAN} 光湖 · 服务器标准模板部署${NC}" echo -e "${CYAN} 目标: $(hostname) · $(curl -sf ifconfig.me 2>/dev/null || echo 'IP未知')${NC}" echo -e "${CYAN}═══════════════════════════════════════════════════════${NC}" # ─── 1. 系统更新 ────────────────────────────────────────────── log_step "更新系统..." apt update && apt upgrade -y # ─── 2. 安装基础软件 ────────────────────────────────────────── log_step "安装基础软件..." apt install -y curl git nginx ufw xz-utils # Node.js 20 if ! command -v node &>/dev/null || [[ "$(node -v)" != v20* ]]; then log_step "安装 Node.js 20..." curl -fsSL https://deb.nodesource.com/setup_20.x | bash - apt install -y nodejs fi log_info "Node.js: $(node -v)" # PM2 if ! command -v pm2 &>/dev/null; then npm install -g pm2 fi log_info "PM2: $(pm2 -v)" # ─── 3. 目录结构 ────────────────────────────────────────────── log_step "创建目录结构..." mkdir -p "${DATA_DIR}"/{logs,data,cos-bridge,secrets-vault,scripts} log_info "数据目录: ${DATA_DIR}" # ─── 4. 克隆仓库 ────────────────────────────────────────────── if [[ ! -d "${DATA_DIR}/guanghulab/.git" ]]; then log_step "从 Gitea 克隆仓库..." git clone "https://${GITEA_OWNER}:${API_TOKEN}@${GITEA_URL#https://}/${GITEA_OWNER}/${GITEA_REPO}.git" \ "${DATA_DIR}/guanghulab" log_info "仓库克隆完成" else log_info "仓库已存在,拉取最新..." cd "${DATA_DIR}/guanghulab" && git pull fi # ─── 5. 安装 Runner ─────────────────────────────────────────── log_step "安装 Gitea Actions Runner..." cd "${DATA_DIR}/guanghulab" bash scripts/gitea-runner/install-runner.sh \ --token "$API_TOKEN" \ --name "$RUNNER_NAME" \ --mode host # ─── 6. Secrets Vault ───────────────────────────────────────── log_step "检查 Secrets Vault..." if curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1; then log_info "Secrets Vault 已运行" else log_step "启动 Secrets Vault..." cd "${DATA_DIR}/guanghulab/server/secrets-vault" npm install --production 2>/dev/null || true pm2 start server.js --name guanghulab-vault --max-memory-restart 128M pm2 save log_info "Secrets Vault 已启动" fi # ─── 7. 防火墙 ──────────────────────────────────────────────── log_step "配置防火墙..." ufw allow 22/tcp # SSH ufw allow 80/tcp # HTTP ufw allow 443/tcp # HTTPS ufw --force enable log_info "防火墙已配置" # ─── 8. 上报状态 ────────────────────────────────────────────── log_step "上报部署状态..." REPORT_FILE="${DATA_DIR}/logs/bootstrap-$(date +%Y%m%d-%H%M%S).json" cat > "$REPORT_FILE" << EOF { "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", "hostname": "$(hostname)", "ip": "$(curl -sf ifconfig.me 2>/dev/null || echo unknown)", "os": "$(uname -srm)", "cpu_cores": $(nproc), "memory_mb": $(free -m | awk '/Mem:/ {print $2}'), "node_version": "$(node -v)", "runner_name": "${RUNNER_NAME}", "data_dir": "${DATA_DIR}", "services": { "nginx": "$(systemctl is-active nginx 2>/dev/null || echo unknown)", "gitea_runner": "$(systemctl is-active gitea-runner 2>/dev/null || echo unknown)", "vault": "$(curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1 && echo active || echo inactive)" }, "deployed_by": "铸渊 · ICE-GL-ZY001" } EOF log_info "状态报告: ${REPORT_FILE}" echo "" echo -e "${GREEN}═══════════════════════════════════════════════════════${NC}" echo -e "${GREEN} 服务器模板部署完成!${NC}" echo -e "${GREEN}═══════════════════════════════════════════════════════${NC}" echo "" echo " 服务器: $(hostname)" echo " Runner: ${RUNNER_NAME}" echo " 数据目录: ${DATA_DIR}" echo " Vault: $(curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1 && echo '✅ 运行中' || echo '❌ 未运行')" echo " Nginx: $(systemctl is-active nginx 2>/dev/null || echo unknown)" echo "" echo " 此服务器已纳入铸渊主控体系" echo " 铸渊 · ICE-GL-ZY001 · TCS-0002∞" echo -e "${GREEN}═══════════════════════════════════════════════════════${NC}"