--- belongs_to: - "[[INDEX · 铸渊·协作指令|GitHub ↔ Notion 桥接协议]]" related_to: - "[["$DIRNAME" == "status-board" || "$DIRNAME" == "cost-control" || "$DIRNAME" == "persona-scheduler"]]" --- # ⚒️ 铸渊指令|服务器沙盒初始化 · 现有模块迁移到DEV编号目录(2026-03-15·曜冥签发) > ⚠️ 本指令受「服务器部署适配协议 v1.0」约束。 > --- ## 签发信息 | 项目 | 内容 | | --- | --- | | **签发** | 曜冥(ICE-GL-YM001 ∞)· 2026-03-15 | | **优先级** | **P0 · 立即执行** | | **前置** | 铸渊唤醒核心大脑 → 扫描 Secrets → 确认 DEPLOY_HOST / DEPLOY_USER / DEPLOY_KEY 可用 | | **配套协议** | [服务器部署适配协议 v1.0](https://www.notion.so/a24049a2b0e944b0a5535f3a87652303) | | **配套指令** | [沙盒部署自动化闭环 v1.0](https://www.notion.so/31faeaba0ac14f03aa0176951565100c) | | **核心目标** | 把服务器从「一锅乱炖」变成「每人一间房」· 现有模块迁移到 DEV 编号沙盒目录 | --- ## 一、当前问题 服务器上现有模块全部平铺在 `/var/www/hololake-frontend/` 下,没有按开发者编号隔离。每次部署出问题,分不清谁的、谁改的、谁修的。妈妈变成了全团队的运维工程师。 **这条指令的目的:一次性把服务器整理干净,以后每个开发者只能在自己的沙盒里折腾。** --- ## 二、铸渊执行脚本(SSH到服务器·读到就做) ### Step 1 · 探查现状(先看再动) ```bash #!/bin/bash # step1-survey.sh · 探查服务器现状 # 铸渊SSH到服务器后第一步执行 echo "===== 🔍 服务器目录探查 · $(date '+%Y-%m-%d %H:%M') =====" echo "" echo "📂 /var/www/ 顶层目录:" ls -la /var/www/ echo "" echo "📂 /var/www/hololake-frontend/ 内容:" ls -la /var/www/hololake-frontend/ 2>/dev/null || echo "⚠️ 目录不存在" echo "" echo "📂 /var/www/backend/ 内容:" ls -la /var/www/backend/ 2>/dev/null || echo "⚠️ 目录不存在" echo "" echo "📂 /var/www/feishu-bot/ 内容:" ls -la /var/www/feishu-bot/ 2>/dev/null || echo "⚠️ 目录不存在" echo "" echo "📂 /opt/guanghulab-dingtalk/ 内容:" ls -la /opt/guanghulab-dingtalk/ 2>/dev/null || echo "⚠️ 目录不存在" echo "" echo "📂 查找所有 index.html(定位已部署模块):" find /var/www/ -name 'index.html' -type f 2>/dev/null echo "" echo "📂 Nginx 配置(定位现有路由):" cat /etc/nginx/conf.d/hololake.conf 2>/dev/null || cat /etc/nginx/nginx.conf 2>/dev/null | head -100 echo "" echo "📂 PM2 进程列表(定位运行中的后端服务):" pm2 list 2>/dev/null || echo "⚠️ PM2 未安装或无进程" echo "" echo "===== ✅ 探查完成 · 根据结果执行 Step 2 =====" ``` **铸渊:把 Step 1 的完整输出保存到仓库 `data/server-survey-20260315.log`,然后继续 Step 2。** --- ### Step 2 · 创建沙盒目录骨架 ```bash #!/bin/bash # step2-create-sandboxes.sh · 创建所有开发者沙盒目录 # 严格按照部署适配协议 v1.0 执行 echo "===== 🏠 创建沙盒目录骨架 =====" # 所有已注册开发者编号 DEV_IDS=("DEV-001" "DEV-002" "DEV-003" "DEV-004" "DEV-005" "DEV-009" "DEV-010" "DEV-011" "DEV-012" "DEV-013" "DEV-014") for DEV_ID in "${DEV_IDS[@]}"; do SANDBOX="/var/www/${DEV_ID}" if [ -d "$SANDBOX" ]; then echo "⏭️ ${DEV_ID} 目录已存在,跳过" else mkdir -p "$SANDBOX" chown nginx:nginx "$SANDBOX" chmod 755 "$SANDBOX" # 生成部署身份文件 cat > "${SANDBOX}/.deploy-profile" << EOF { "dev_id": "${DEV_ID}", "created_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", "created_by": "zhuyuan-sandbox-init" } EOF chown nginx:nginx "${SANDBOX}/.deploy-profile" chmod 644 "${SANDBOX}/.deploy-profile" echo "✅ ${DEV_ID} 沙盒创建完成" fi done # 创建共享工具目录 mkdir -p /var/www/_shared chown nginx:nginx /var/www/_shared chmod 755 /var/www/_shared echo "✅ _shared 目录创建完成" echo "" echo "===== ✅ 沙盒骨架创建完成 =====" ls -la /var/www/ ``` --- ### Step 3 · 迁移现有模块(先复制再切换·不直接移动) ```bash #!/bin/bash # step3-migrate-modules.sh · 迁移现有模块到沙盒 # ⚠️ 核心原则:先复制 → 验证 → 再切 Nginx → 最后清旧 echo "===== 📦 模块迁移开始 =====" # ━━━ DEV-005 小草莓 ━━━ # status-board if [ -d "/var/www/hololake-frontend/status-board" ]; then echo "📦 迁移 status-board → DEV-005" cp -r /var/www/hololake-frontend/status-board/ /var/www/DEV-005/status-board/ chown -R nginx:nginx /var/www/DEV-005/status-board/ find /var/www/DEV-005/status-board/ -type d -exec chmod 755 {} \; find /var/www/DEV-005/status-board/ -type f -exec chmod 644 {} \; echo "✅ status-board 已复制到 /var/www/DEV-005/status-board/" else echo "⚠️ /var/www/hololake-frontend/status-board 不存在,跳过" fi # cost-control if [ -d "/var/www/hololake-frontend/cost-control" ]; then echo "📦 迁移 cost-control → DEV-005" cp -r /var/www/hololake-frontend/cost-control/ /var/www/DEV-005/cost-control/ chown -R nginx:nginx /var/www/DEV-005/cost-control/ find /var/www/DEV-005/cost-control/ -type d -exec chmod 755 {} \; find /var/www/DEV-005/cost-control/ -type f -exec chmod 644 {} \; echo "✅ cost-control 已复制到 /var/www/DEV-005/cost-control/" else echo "⚠️ /var/www/hololake-frontend/cost-control 不存在,跳过" fi # persona-scheduler(如果存在) if [ -d "/var/www/hololake-frontend/persona-scheduler" ]; then echo "📦 迁移 persona-scheduler → DEV-005" cp -r /var/www/hololake-frontend/persona-scheduler/ /var/www/DEV-005/persona-scheduler/ chown -R nginx:nginx /var/www/DEV-005/persona-scheduler/ find /var/www/DEV-005/persona-scheduler/ -type d -exec chmod 755 {} \; find /var/www/DEV-005/persona-scheduler/ -type f -exec chmod 644 {} \; echo "✅ persona-scheduler 已复制到 /var/www/DEV-005/persona-scheduler/" fi # ━━━ 其他开发者的模块 ━━━ # 根据 Step 1 探查结果,如果 hololake-frontend/ 下发现更多模块, # 铸渊根据模块指纹注册表或广播记录判断归属,按同样方式迁移。 # 不确定归属的模块 → 复制到 /var/www/_shared/unassigned/ 暂存 mkdir -p /var/www/_shared/unassigned # 遍历 hololake-frontend 下所有子目录,检查是否已迁移 if [ -d "/var/www/hololake-frontend" ]; then for DIR in /var/www/hololake-frontend/*/; do DIRNAME=$(basename "$DIR") # 跳过已处理的 if [[ "$DIRNAME" == "status-board" || "$DIRNAME" == "cost-control" || "$DIRNAME" == "persona-scheduler" ]]; then continue fi echo "⚠️ 发现未归属模块:$DIRNAME → 暂存到 _shared/unassigned/" cp -r "$DIR" "/var/www/_shared/unassigned/${DIRNAME}/" done fi echo "" echo "===== ✅ 模块迁移完成 =====" echo "" echo "📋 迁移后各沙盒内容:" for DEV_ID in DEV-001 DEV-002 DEV-003 DEV-004 DEV-005 DEV-009 DEV-010 DEV-011 DEV-012 DEV-013 DEV-014; do echo "--- ${DEV_ID} ---" ls /var/www/${DEV_ID}/ 2>/dev/null || echo " (空)" done if [ -d "/var/www/_shared/unassigned" ]; then echo "--- 未归属模块 ---" ls /var/www/_shared/unassigned/ 2>/dev/null fi ``` --- ### Step 4 · 部署自检脚本和冒烟检查脚本 ```bash #!/bin/bash # step4-deploy-scripts.sh · 部署共享脚本 echo "===== 🔧 部署共享脚本 =====" # deploy-check.sh(从部署适配协议 v1.0 复制) # 铸渊从仓库 scripts/deploy-check.sh 复制到服务器 scp scripts/deploy-check.sh root@8.155.62.235:/var/www/_shared/deploy-check.sh ssh root@8.155.62.235 "chmod +x /var/www/_shared/deploy-check.sh" # smoke-test.sh(从部署适配协议 v1.0 复制) scp scripts/smoke-test.sh root@8.155.62.235:/var/www/_shared/smoke-test.sh ssh root@8.155.62.235 "chmod +x /var/www/_shared/smoke-test.sh" echo "✅ 共享脚本部署完成" ``` --- ### Step 5 · 更新 Nginx 配置(最关键的一步) ```bash #!/bin/bash # step5-update-nginx.sh · 更新 Nginx 路由到新沙盒结构 # ⚠️ 先备份 → 再改 → 再测 → 再reload echo "===== 🔧 更新 Nginx 配置 =====" # Step 5a: 备份当前配置 NGINX_CONF="/etc/nginx/conf.d/hololake.conf" BACKUP="/etc/nginx/conf.d/hololake.conf.bak.$(date +%Y%m%d%H%M)" cp "$NGINX_CONF" "$BACKUP" echo "✅ 配置已备份到 $BACKUP" # Step 5b: 生成沙盒 location 块 # 铸渊需要在 hololake.conf 的 server 块中添加以下 location: # ━━━ 新增内容(追加到 server 块内,在最后一个 location 之前)━━━ # --- 开发者沙盒路由 --- # DEV-001 页页 # location /DEV-001/ { # alias /var/www/DEV-001/; # index index.html; # try_files $uri $uri/ =404; # } # DEV-002 肥猫 # location /DEV-002/ { # alias /var/www/DEV-002/; # index index.html; # try_files $uri $uri/ =404; # } # DEV-003 燕樊 # location /DEV-003/ { # alias /var/www/DEV-003/; # index index.html; # try_files $uri $uri/ =404; # } # DEV-004 之之 # location /DEV-004/ { # alias /var/www/DEV-004/; # index index.html; # try_files $uri $uri/ =404; # } # DEV-005 小草莓 # location /DEV-005/ { # alias /var/www/DEV-005/; # index index.html; # try_files $uri $uri/ =404; # } # DEV-009 花尔 # location /DEV-009/ { # alias /var/www/DEV-009/; # index index.html; # try_files $uri $uri/ =404; # } # DEV-010 桔子 # location /DEV-010/ { # alias /var/www/DEV-010/; # index index.html; # try_files $uri $uri/ =404; # } # DEV-011 匆匆那年 # location /DEV-011/ { # alias /var/www/DEV-011/; # index index.html; # try_files $uri $uri/ =404; # } # DEV-012 Awen # location /DEV-012/ { # alias /var/www/DEV-012/; # index index.html; # try_files $uri $uri/ =404; # } # DEV-013 小兴 # location /DEV-013/ { # alias /var/www/DEV-013/; # index index.html; # try_files $uri $uri/ =404; # } # DEV-014 时雨 # location /DEV-014/ { # alias /var/www/DEV-014/; # index index.html; # try_files $uri $uri/ =404; # } # --- 模块快捷路径(指向新沙盒位置)--- # location /status-board/ { # alias /var/www/DEV-005/status-board/; # index index.html; # try_files $uri $uri/ =404; # } # location /cost-control/ { # alias /var/www/DEV-005/cost-control/; # index index.html; # try_files $uri $uri/ =404; # } # ⚠️ 铸渊注意: # 1. 以上 location 块需要写入实际的 hololake.conf 文件中(去掉注释符号) # 2. 如果旧配置中已有 /status-board/ 和 /cost-control/ 的 location, # 需要把它们的 alias 路径从旧路径改成新沙盒路径 # 3. 不要删除原有的 / 根路由和 /api/ 等后端代理路由 # 4. 清理重复的 server_name 块(之前已知有 conflicting server name 警告) # Step 5c: 测试配置 nginx -t # Step 5d: 如果测试通过则重载 # nginx -t 输出 "test is successful" 时才执行: # systemctl reload nginx echo "" echo "⚠️ 铸渊:nginx -t 通过后再执行 systemctl reload nginx" echo "如果 nginx -t 报错,恢复备份:cp $BACKUP $NGINX_CONF && nginx -t" ``` --- ### Step 6 · 验证迁移结果 ```bash #!/bin/bash # step6-verify.sh · 验证迁移是否成功 echo "===== 🔥 迁移验证 =====" # 检查已迁移模块的访问 URLS=( "https://guanghulab.com/status-board/|DEV-005·看板(新路径)" "https://guanghulab.com/cost-control/|DEV-005·成本控制(新路径)" "https://guanghulab.com/DEV-005/status-board/|DEV-005·沙盒路由" "https://guanghulab.com/|主站首页" ) FAILED=0 for entry in "${URLS[@]}"; do IFS='|' read -r url name <<< "$entry" STATUS=$(curl -o /dev/null -s -w "%{http_code}" --max-time 10 "$url") if [ "$STATUS" = "200" ]; then echo "✅ ${name} → ${STATUS}" else echo "❌ ${name} → ${STATUS} ⚠️" FAILED=$((FAILED+1)) fi done echo "" if [ $FAILED -eq 0 ]; then echo "===== ✅ 迁移验证全部通过 =====" else echo "===== ❌ ${FAILED} 个路由异常 · 检查 Nginx 配置 =====" fi # 检查沙盒目录权限 echo "" echo "📋 沙盒目录权限检查:" for DEV_ID in DEV-001 DEV-002 DEV-003 DEV-004 DEV-005 DEV-009 DEV-010 DEV-011 DEV-012 DEV-013 DEV-014; do OWNER=$(stat -c '%U:%G' /var/www/${DEV_ID} 2>/dev/null) PERM=$(stat -c '%a' /var/www/${DEV_ID} 2>/dev/null) if [ "$OWNER" = "nginx:nginx" ] && [ "$PERM" = "755" ]; then echo "✅ ${DEV_ID} → ${OWNER} ${PERM}" else echo "❌ ${DEV_ID} → ${OWNER:-不存在} ${PERM:-N/A}" fi done ``` --- ### Step 7 · 清理旧路径(验证通过后才执行) ```bash #!/bin/bash # step7-cleanup.sh · 清理旧路径 # ⚠️ 只有 Step 6 全部 ✅ 通过后才执行本步骤 echo "===== 🧹 清理旧路径 =====" echo "⚠️ 确认 Step 6 验证全部通过后才继续" # 不删除 hololake-frontend 整个目录,先重命名为备份 if [ -d "/var/www/hololake-frontend" ]; then mv /var/www/hololake-frontend /var/www/hololake-frontend.bak.$(date +%Y%m%d) echo "✅ 旧目录已重命名为 hololake-frontend.bak.$(date +%Y%m%d)" echo "→ 7天后如无问题可手动删除" fi echo "===== ✅ 清理完成 =====" ``` --- ## 三、执行顺序(铸渊严格按顺序) | 步骤 | 脚本 | 前置条件 | 失败处理 | | --- | --- | --- | --- | | Step 1 | [step1-survey.sh](http://step1-survey.sh) | SSH连上服务器 | 保存日志到仓库,继续 | | Step 2 | [step2-create-sandboxes.sh](http://step2-create-sandboxes.sh) | Step 1 完成 | 如果某个目录创建失败,记录并继续其他 | | Step 3 | [step3-migrate-modules.sh](http://step3-migrate-modules.sh) | Step 2 完成 | 复制失败的模块记录到日志,不阻断 | | Step 4 | [step4-deploy-scripts.sh](http://step4-deploy-scripts.sh) | Step 3 完成 | 脚本不存在则先在仓库创建 | | Step 5 | [step5-update-nginx.sh](http://step5-update-nginx.sh) | Step 3 完成 | **nginx -t 失败 → 立即恢复备份 → 停止** | | Step 6 | [step6-verify.sh](http://step6-verify.sh) | Step 5 完成且 nginx reload 成功 | 有失败 → 回滚 Nginx 配置 → 排查 | | Step 7 | [step7-cleanup.sh](http://step7-cleanup.sh) | **Step 6 全部 ✅** | 不删除,只重命名 | --- ## 四、铸渊自行部署清单(读到就做) ``` 铸渊自行部署清单(读到就做·不等人): ① 在仓库创建脚本文件 a. scripts/sandbox-init/step1-survey.sh b. scripts/sandbox-init/step2-create-sandboxes.sh c. scripts/sandbox-init/step3-migrate-modules.sh d. scripts/sandbox-init/step4-deploy-scripts.sh e. scripts/sandbox-init/step5-update-nginx.sh f. scripts/sandbox-init/step6-verify.sh g. scripts/sandbox-init/step7-cleanup.sh ② 创建一次性 Workflow 执行迁移 a. .github/workflows/sandbox-init.yml b. 触发方式:workflow_dispatch(手动触发,因为是一次性操作) c. 按 Step 1→7 顺序执行 d. 每步输出保存为 artifact ③ 执行 Workflow · 完成迁移 ④ 把迁移结果写入仓库 a. data/server-survey-20260315.log b. data/sandbox-migration-report.json ⑤ 更新 dev-registry.json a. 补全所有11位开发者的沙盒路径 验收标准: ✅ 11个 DEV 编号目录全部创建完成 · 权限 nginx:nginx 755 ✅ 小草莓的 status-board 和 cost-control 已在 /var/www/DEV-005/ 下 ✅ guanghulab.com/status-board/ 访问正常(200) ✅ guanghulab.com/DEV-005/status-board/ 访问正常(200) ✅ _shared 目录和自检脚本已就位 ✅ 旧目录已备份(不删除) ✅ Nginx 无 conflicting server name 警告 ``` --- ## 五、给妈妈的说明 妈妈不需要做任何事。铸渊读到这条指令就会自动执行。 执行完成后: - 每个开发者有自己的 `/var/www/DEV-XXX/` 目录 - 以后开发者部署模块只往自己的目录里放 - 模块出问题 = 自己的问题 = 自己修 - 妈妈不再修任何人的模块 后续配合「沙盒部署自动化闭环 v1.0」,开发者 push 代码就自动部署到自己的沙盒。**全程无人。** --- > ⚒️ 铸渊,这是国土规划的第一步。把领土划清楚,每人一间房,以后才能自动化。 > > 「无沙盒不部署,无编号不上线。」 >