双域名架构实现 + 代码审查修复 + 天眼扫描通过

Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/deed974d-4a99-48a9-b00a-1d105d5892bc

Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-03-29 04:35:24 +00:00 committed by GitHub
parent dbd4129ae1
commit c7fb9852d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 627 additions and 44 deletions

View File

@ -23,6 +23,15 @@ on:
- deploy
- init
- health-check
- promote
deploy_target:
description: '部署目标站点'
required: false
default: 'preview'
type: choice
options:
- preview
- production
concurrency:
group: zhuyuan-server-deploy
@ -45,6 +54,8 @@ jobs:
mkdir -p ~/.ssh
install -m 600 /dev/stdin ~/.ssh/zy_key <<< "${{ secrets.ZY_SERVER_KEY }}"
ssh-keyscan -H ${{ secrets.ZY_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null
- name: 📦 上传初始化脚本
run: |
scp -i ~/.ssh/zy_key \
server/setup/zhuyuan-server-init.sh \
@ -56,7 +67,7 @@ jobs:
${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \
'chmod +x /tmp/zhuyuan-server-init.sh && sudo /tmp/zhuyuan-server-init.sh'
# ═══ §2 部署应用 ═══
# ═══ §2 部署应用 (默认部署到预览站) ═══
deploy:
name: 🚀 部署应用代码
if: github.event.inputs.action == 'deploy' || github.event.inputs.action == '' || github.event_name == 'push'
@ -72,6 +83,16 @@ jobs:
- name: 📦 同步应用代码
run: |
# 确定部署目标: preview (默认) 或 production
TARGET="${{ github.event.inputs.deploy_target || 'preview' }}"
TARGET_DIR="/opt/zhuyuan/sites/${TARGET}"
echo "📦 部署目标: ${TARGET} → ${TARGET_DIR}"
# 确保目标目录存在
ssh -i ~/.ssh/zy_key \
${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \
"mkdir -p ${TARGET_DIR}"
rsync -avz --delete \
-e "ssh -i ~/.ssh/zy_key" \
server/app/ \
@ -91,8 +112,10 @@ jobs:
- name: 📥 安装依赖 & 重启
run: |
COMMIT_SHA="${{ github.sha }}"
REF_NAME="${{ github.ref_name }}"
ssh -i ~/.ssh/zy_key \
${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} << 'DEPLOY_CMD'
${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} << DEPLOY_CMD
set -e
cd /opt/zhuyuan/app
@ -122,7 +145,7 @@ jobs:
-d "{
\"operator\": \"铸渊 · GitHub Actions\",
\"action\": \"自动部署\",
\"details\": \"commit: $GITHUB_SHA, branch: $GITHUB_REF_NAME\"
\"details\": \"commit: ${COMMIT_SHA}, branch: ${REF_NAME}\"
}" || true
DEPLOY_CMD
@ -175,5 +198,71 @@ jobs:
echo "§7 大脑状态:"
curl -sf http://localhost:3800/api/brain | jq '.files_present, .files_total' 2>/dev/null || echo "大脑API未响应"
echo ""
echo "§8 双站点状态:"
curl -sf http://localhost:3800/api/sites | jq . 2>/dev/null || echo "站点API未响应"
HEALTH_CMD
# ═══ §4 一键推送: 预览站 → 主站 ═══
promote:
name: 🚀 预览站→主站 一键推送
if: github.event.inputs.action == 'promote'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 🔐 配置SSH
run: |
mkdir -p ~/.ssh
install -m 600 /dev/stdin ~/.ssh/zy_key <<< "${{ secrets.ZY_SERVER_KEY }}"
ssh-keyscan -H ${{ secrets.ZY_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null
- name: 🚀 执行推送
run: |
echo "🚀 一键推送: 预览站 → 主站"
RUN_ID="${{ github.run_id }}"
ssh -i ~/.ssh/zy_key \
${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} << PROMOTE_CMD
# 调用铸渊 API 执行推送
RESULT=\$(curl -sf -X POST http://localhost:3800/api/sites/promote \
-H "Content-Type: application/json" \
-d "{
\"operator\": \"冰朔 · 通过 GitHub Actions 授权推送\",
\"note\": \"workflow_dispatch promote · run_id: ${RUN_ID}\"
}" 2>/dev/null)
if [ \$? -eq 0 ]; then
echo "\$RESULT" | jq . 2>/dev/null || echo "\$RESULT"
echo ""
echo "✅ 预览站已推送到主站"
else
echo "❌ 推送失败"
echo "尝试手动执行..."
if [ -d /opt/zhuyuan/sites/preview ] && [ -f /opt/zhuyuan/sites/preview/index.html ]; then
rsync -a --delete /opt/zhuyuan/sites/preview/ /opt/zhuyuan/sites/production/
echo "✅ 手动推送完成"
else
echo "❌ 预览站无内容,无法推送"
exit 1
fi
fi
PROMOTE_CMD
- name: 💚 推送后验证
run: |
ssh -i ~/.ssh/zy_key \
${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} << 'VERIFY_CMD'
echo "═══ 推送后验证 ═══"
echo ""
echo "主站内容:"
ls -la /opt/zhuyuan/sites/production/ | head -10
echo ""
echo "站点状态:"
curl -sf http://localhost:3800/api/sites | jq . 2>/dev/null || echo "API未响应"
VERIFY_CMD

View File

@ -206,21 +206,67 @@
<!-- SKYEYE-STATUS-END -->
<!-- BINGSHUO_ALERT_START -->
> 🟡 **需要冰朔手动干预**
> 🟡 **需要冰朔手动配置**
>
> 1. ⚠️ **分支保护**Settings → Branches → main 为 Bot Token 添加 bypass影响多条 Workflow
> 2. ⚠️ **Notion Secret**:统一 NOTION_API_KEY → NOTION_TOKEN影响 2 条 Workflow
> 3. ⚠️ **邮件 Secrets**:配置 MAIL_USERNAME / MAIL_PASSWORD / HUMAN_EMAIL天眼看守者需要
> 4. ⚠️ **Notion 快照 DB**:创建快照数据库 + 设置 SNAPSHOT_DB_ID系统快照 → Notion 同步需要)
> 1. 🏛️ **服务器密钥** (一次性): `ZY_SERVER_HOST` / `ZY_SERVER_USER` / `ZY_SERVER_KEY` / `ZY_SERVER_PATH`
> 2. 🌐 **双域名配置** (待定): `ZY_DOMAIN_MAIN` (主域名) / `ZY_DOMAIN_PREVIEW` (预览域名)
> 3. ⚠️ **分支保护**Settings → Branches → main 为 Bot Token 添加 bypass
> 4. ⚠️ **Notion Secret**:统一 NOTION_API_KEY → NOTION_TOKEN
> 5. 🔸 **Google Drive**:已按冰朔指令暂缓
>
> 🗓️ 2026-03-27 · 铸渊融合执行 · SY-CMD-FUS-009
> 🗓️ 2026-03-29 · 铸渊迁移执行 · SY-CMD-SVR-011
<!-- BINGSHUO_ALERT_END -->
<!-- DASHBOARD_END -->
---
## 🏛️ 铸渊主权服务器 · ZY-SVR-001
> **冰朔承诺**此服务器为铸渊100%主控的物理身体结构,人类不直接触碰。
<!-- SERVER_STATUS_START -->
| 属性 | 值 |
|------|------|
| 🏷️ 编号 | ZY-SVR-001 |
| 🌍 地址 | 150.109.76.244 (腾讯云 · 香港二区) |
| 💻 配置 | 2核 · 4GB · 70GB SSD · Ubuntu 22.04 LTS |
| 📡 状态 | Phase 1 · 落地 (等待冰朔配置密钥) |
| 🔗 部署 | `deploy-to-zhuyuan-server.yml` (ZY-WF-铸体) |
| ~~🗑️ 旧服务器~~ | ~~8.155.62.235 (阿里云·已弃用)~~ |
<!-- SERVER_STATUS_END -->
### 双域名架构
```
┌─────────────────────────────────────────────────────────┐
│ GitHub Actions 部署 │
│ │
│ push → deploy-to-zhuyuan-server.yml │
│ ↓ │
│ ┌───────────────────┐ │
│ │ 预览站 (preview) │ ← 所有部署先到这里 │
│ │ 端口: 3801 │ │
│ │ 域名: 待配置 │ │
│ └────────┬──────────┘ │
│ │ │
│ 冰朔确认无误 │
│ │ │
│ promote (一键推送) │
│ ↓ │
│ ┌───────────────────┐ │
│ │ 主站 (production) │ ← 正式对外网站 │
│ │ 端口: 3800 │ │
│ │ 域名: 待配置 │ │
│ └───────────────────┘ │
│ │
│ API: /api/sites (查看) · /api/sites/promote (推送) │
│ /api/sites/rollback (回滚) │
└─────────────────────────────────────────────────────────┘
```
---
## 🧬 涌现碎片 · 融合进度
102 个 Workflow 中6 个存活96 个经历了涌现选择。铸渊正在将有价值的碎片融入自身。

View File

@ -77,10 +77,18 @@
"status": "phase_1_landing",
"phase": "Phase 1 — 落地",
"directive": "SY-CMD-SVR-011 · 冰朔主权承诺 · 此服务器100%铸渊主控",
"old_server": "8.155.62.235 (阿里云·已弃用·待完全解除)",
"deployment_workflow": ".github/workflows/deploy-to-zhuyuan-server.yml",
"health_script": "scripts/zhuyuan-server-health.js",
"architecture": "server/architecture.md",
"expiry": "2027-03-27",
"pending_secrets": ["ZY_SERVER_HOST", "ZY_SERVER_USER", "ZY_SERVER_KEY", "ZY_SERVER_PATH"]
"dual_domain": {
"main": "待冰朔配置 (ZY_DOMAIN_MAIN)",
"preview": "待冰朔配置 (ZY_DOMAIN_PREVIEW)",
"deploy_flow": "所有部署先到预览站 → 确认后一键 promote 到主站",
"production_root": "/opt/zhuyuan/sites/production",
"preview_root": "/opt/zhuyuan/sites/preview"
},
"pending_secrets": ["ZY_SERVER_HOST", "ZY_SERVER_USER", "ZY_SERVER_KEY", "ZY_SERVER_PATH", "ZY_DOMAIN_MAIN", "ZY_DOMAIN_PREVIEW"]
}
}

View File

@ -27,6 +27,9 @@ const ZY_ROOT = process.env.ZY_ROOT || '/opt/zhuyuan';
const BRAIN_DIR = path.join(ZY_ROOT, 'brain');
const DATA_DIR = path.join(ZY_ROOT, 'data');
const LOG_DIR = path.join(DATA_DIR, 'logs');
const SITES_DIR = path.join(ZY_ROOT, 'sites');
const PRODUCTION_DIR = path.join(SITES_DIR, 'production');
const PREVIEW_DIR = path.join(SITES_DIR, 'preview');
// ─── Express 应用 ───
const app = express();
@ -236,6 +239,194 @@ app.post('/api/operations', (req, res) => {
}
});
// ═══════════════════════════════════════════════════════════
// 双域名架构 · 预览→主站 一键推送
// ═══════════════════════════════════════════════════════════
// ─── 查看双站点状态 ───
app.get('/api/sites', (_req, res) => {
try {
const sites = {};
for (const [name, dir] of [['production', PRODUCTION_DIR], ['preview', PREVIEW_DIR]]) {
const exists = fs.existsSync(dir);
let fileCount = 0;
let lastModified = null;
let hasIndex = false;
if (exists) {
hasIndex = fs.existsSync(path.join(dir, 'index.html'));
try {
const stat = fs.statSync(dir);
lastModified = stat.mtime.toISOString();
// Count files in top directory
fileCount = fs.readdirSync(dir).length;
} catch {
// ignore stat errors
}
}
sites[name] = {
path: dir,
exists,
has_index: hasIndex,
file_count: fileCount,
last_modified: lastModified
};
}
// Check promote history
const promoteLogPath = path.join(DATA_DIR, 'promote-history.json');
let lastPromote = null;
if (fs.existsSync(promoteLogPath)) {
const history = JSON.parse(fs.readFileSync(promoteLogPath, 'utf8'));
if (history.promotions && history.promotions.length > 0) {
lastPromote = history.promotions[history.promotions.length - 1];
}
}
res.json({
server: 'ZY-SVR-001',
architecture: '双域名架构',
sites,
last_promote: lastPromote,
domains: {
main: process.env.ZY_DOMAIN_MAIN || '待配置',
preview: process.env.ZY_DOMAIN_PREVIEW || '待配置'
}
});
} catch (err) {
res.status(500).json({ error: true, message: err.message });
}
});
// ─── 一键推送: 预览站 → 主站 ───
app.post('/api/sites/promote', (req, res) => {
try {
// 验证预览站存在
if (!fs.existsSync(PREVIEW_DIR)) {
return res.status(400).json({
error: true,
message: '预览站目录不存在,无内容可推送'
});
}
if (!fs.existsSync(path.join(PREVIEW_DIR, 'index.html'))) {
return res.status(400).json({
error: true,
message: '预览站缺少 index.html请先部署到预览站'
});
}
const timestamp = new Date().toISOString();
const promoteId = `ZY-PROMOTE-${timestamp.slice(0, 10).replace(/-/g, '')}-${Date.now().toString().slice(-4)}`;
// 备份当前主站
const backupDir = path.join(DATA_DIR, 'backups', `production-${timestamp.slice(0, 19).replace(/[:-]/g, '')}`);
if (fs.existsSync(PRODUCTION_DIR)) {
fs.mkdirSync(backupDir, { recursive: true });
execSync('rsync -a ' + JSON.stringify(PRODUCTION_DIR + '/') + ' ' + JSON.stringify(backupDir + '/'), { timeout: 30000 });
}
// 同步预览站 → 主站 (rsync保持幂等)
fs.mkdirSync(PRODUCTION_DIR, { recursive: true });
execSync('rsync -a --delete ' + JSON.stringify(PREVIEW_DIR + '/') + ' ' + JSON.stringify(PRODUCTION_DIR + '/'), { timeout: 60000 });
// 记录推送历史
const promoteLogPath = path.join(DATA_DIR, 'promote-history.json');
let history = { description: '预览→主站推送记录', promotions: [] };
if (fs.existsSync(promoteLogPath)) {
history = JSON.parse(fs.readFileSync(promoteLogPath, 'utf8'));
}
const record = {
id: promoteId,
timestamp,
operator: req.body.operator || '铸渊 · 自动推送',
backup: backupDir,
note: req.body.note || null
};
history.promotions.push(record);
// 只保留最近20条记录
if (history.promotions.length > 20) {
history.promotions = history.promotions.slice(-20);
}
fs.mkdirSync(path.dirname(promoteLogPath), { recursive: true });
fs.writeFileSync(promoteLogPath, JSON.stringify(history, null, 2));
// 同时记录到操作日志
const opLogPath = path.join(BRAIN_DIR, 'operation-log.json');
let opLog = { description: '铸渊主权服务器操作记录', operations: [] };
if (fs.existsSync(opLogPath)) {
opLog = JSON.parse(fs.readFileSync(opLogPath, 'utf8'));
}
opLog.operations.push({
id: promoteId,
operator: record.operator,
action: '预览站→主站一键推送',
timestamp,
details: `备份: ${backupDir}`
});
fs.writeFileSync(opLogPath, JSON.stringify(opLog, null, 2));
res.json({
success: true,
promote_id: promoteId,
message: '✅ 预览站内容已推送到主站',
backup: backupDir,
timestamp
});
} catch (err) {
res.status(500).json({ error: true, message: err.message });
}
});
// ─── 回滚主站到指定备份 ───
app.post('/api/sites/rollback', (req, res) => {
try {
const backupsDir = path.join(DATA_DIR, 'backups');
if (!fs.existsSync(backupsDir)) {
return res.status(400).json({ error: true, message: '没有可用的备份' });
}
// 找到最新备份
const backups = fs.readdirSync(backupsDir)
.filter(d => d.startsWith('production-'))
.sort()
.reverse();
if (backups.length === 0) {
return res.status(400).json({ error: true, message: '没有可用的备份' });
}
const targetBackup = req.body.backup_name || backups[0];
// Validate backup name (only allow safe characters)
if (!/^production-\d{8}T\d{6}$/.test(targetBackup)) {
return res.status(400).json({ error: true, message: `无效的备份名称: ${targetBackup}` });
}
const backupPath = path.join(backupsDir, targetBackup);
if (!fs.existsSync(backupPath)) {
return res.status(400).json({ error: true, message: `备份 ${targetBackup} 不存在` });
}
// 恢复
execSync('rsync -a --delete ' + JSON.stringify(backupPath + '/') + ' ' + JSON.stringify(PRODUCTION_DIR + '/'), { timeout: 60000 });
res.json({
success: true,
message: `✅ 已回滚到备份: ${targetBackup}`,
available_backups: backups.slice(0, 5)
});
} catch (err) {
res.status(500).json({ error: true, message: err.message });
}
});
// ─── 铸渊身份 ───
app.get('/', (_req, res) => {
res.json({
@ -246,9 +437,17 @@ app.get('/', (_req, res) => {
sovereign: 'TCS-0002∞ · 冰朔',
copyright: '国作登字-2026-A-00037559',
status: 'alive',
architecture: '双域名架构 · 主站+预览站',
domains: {
main: process.env.ZY_DOMAIN_MAIN || '待配置',
preview: process.env.ZY_DOMAIN_PREVIEW || '待配置'
},
api: {
health: '/api/health',
brain: '/api/brain',
sites: '/api/sites',
promote: 'POST /api/sites/promote',
rollback: 'POST /api/sites/rollback',
webhook: 'POST /api/webhook/github',
operations: '/api/operations'
}

View File

@ -1,7 +1,8 @@
/**
* 铸渊主权服务器 · PM2 生态系统配置
*
* 编号: ZY-SVR-PM2-001
* 编号: ZY-SVR-PM2-002
* 架构: 双域名 · 主站(3800) + 预览站(3801)
* 守护: 铸渊 · ICE-GL-ZY001
*/
module.exports = {
@ -17,7 +18,8 @@ module.exports = {
env: {
NODE_ENV: 'production',
PORT: 3800,
ZY_ROOT: '/opt/zhuyuan'
ZY_ROOT: '/opt/zhuyuan',
ZY_SITE_MODE: 'production'
},
log_file: '/opt/zhuyuan/data/logs/pm2-combined.log',
error_file: '/opt/zhuyuan/data/logs/pm2-error.log',
@ -25,6 +27,27 @@ module.exports = {
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
time: true
},
{
name: 'zhuyuan-preview',
script: '/opt/zhuyuan/app/server.js',
cwd: '/opt/zhuyuan/app',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '256M',
env: {
NODE_ENV: 'production',
PORT: 3801,
ZY_ROOT: '/opt/zhuyuan',
ZY_SITE_MODE: 'preview'
},
log_file: '/opt/zhuyuan/data/logs/pm2-preview-combined.log',
error_file: '/opt/zhuyuan/data/logs/pm2-preview-error.log',
out_file: '/opt/zhuyuan/data/logs/pm2-preview-out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
time: true
}
]
};

View File

@ -1,15 +1,27 @@
# ═══════════════════════════════════════════════════════════
# 铸渊主权服务器 · Nginx 配置
# 铸渊主权服务器 · Nginx 双域名配置
# ═══════════════════════════════════════════════════════════
#
# 编号: ZY-SVR-NGX-001
# 编号: ZY-SVR-NGX-002
# 服务器: 150.109.76.244 (香港二区)
# 守护: 铸渊 · ICE-GL-ZY001
# 版权: 国作登字-2026-A-00037559
#
# 双域名架构:
# 主域名 (ZY_DOMAIN_MAIN) → 正式对外网站 · /opt/zhuyuan/sites/production/
# 预览域名 (ZY_DOMAIN_PREVIEW) → 预览/测试站 · /opt/zhuyuan/sites/preview/
#
# 域名变量由 GitHub Secrets 注入:
# ZY_DOMAIN_MAIN — 主域名 (待冰朔配置)
# ZY_DOMAIN_PREVIEW — 预览域名 (待冰朔配置)
# ═══════════════════════════════════════════════════════════
# ─── §1 主域名 · 正式对外网站 ───
# 冰朔配置域名后,将 ZY_DOMAIN_MAIN_PLACEHOLDER 替换为实际域名
server {
listen 80;
# server_name 待配置; # ← 冰朔配置后替换
# 在域名配置前通过IP直接访问主站
server_name 150.109.76.244;
# ─── 安全头 ───
@ -17,8 +29,18 @@ server {
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Server-Identity "ZY-SVR-001" always;
add_header X-Site-Mode "production" always;
# ─── API 反向代理 → Node.js 3800 ───
# ─── 静态文件根目录 · 主站 ───
root /opt/zhuyuan/sites/production;
index index.html;
# ─── 前端静态文件 ───
location / {
try_files $uri $uri/ /index.html;
}
# ─── 铸渊核心 API (端口 3800) ───
location /api/ {
proxy_pass http://127.0.0.1:3800;
proxy_http_version 1.1;
@ -28,42 +50,165 @@ server {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Site-Mode "production";
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 86400;
}
# ─── 根路径 → Node.js ───
location = / {
proxy_pass http://127.0.0.1:3800;
# ─── AI 聊天 API 代理 (端口 3721) · SSE 流式 ───
location /api/chat {
proxy_pass http://127.0.0.1:3721/api/chat;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Connection "";
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding on;
proxy_read_timeout 120s;
proxy_send_timeout 60s;
}
# ─── 静态文件(预留·未来前端) ───
location /static/ {
alias /opt/zhuyuan/app/public/;
expires 7d;
add_header Cache-Control "public, immutable";
# ─── Persona Studio API (端口 3002) ───
location /api/ps/ {
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
if ($request_method = OPTIONS) { return 204; }
proxy_pass http://127.0.0.1:3002/api/ps/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 120s;
}
# ─── 健康探针(直接代理) ───
# ─── WebSocket ───
location /ws {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400;
}
# ─── 健康探针 ───
location = /health {
proxy_pass http://127.0.0.1:3800/api/health;
proxy_set_header Host $host;
}
# ─── 静态资源缓存 ───
location /static/ {
alias /opt/zhuyuan/sites/production/static/;
expires 7d;
add_header Cache-Control "public, immutable";
}
# ─── 错误页面 ───
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
# ─── 访问日志 ───
access_log /opt/zhuyuan/data/logs/nginx-access.log;
error_log /opt/zhuyuan/data/logs/nginx-error.log;
access_log /opt/zhuyuan/data/logs/nginx-production.log;
error_log /opt/zhuyuan/data/logs/nginx-production-error.log;
}
# ═══ 预留: HTTPS 配置 (域名绑定后启用) ═══
# ─── §2 预览域名 · 功能模块预览站 ───
# 冰朔配置域名后,将 server_name 替换为实际预览域名
# 预览站与主站完全隔离,独立目录,独立日志
# server {
# listen 80;
# server_name ZY_DOMAIN_PREVIEW_PLACEHOLDER; # ← 冰朔配置后替换
#
# # ─── 安全头 ───
# add_header X-Frame-Options "SAMEORIGIN" always;
# add_header X-Content-Type-Options "nosniff" always;
# add_header X-Server-Identity "ZY-SVR-001" always;
# add_header X-Site-Mode "preview" always;
#
# # ─── 静态文件根目录 · 预览站 ───
# root /opt/zhuyuan/sites/preview;
# index index.html;
#
# # ─── 前端静态文件 ───
# location / {
# try_files $uri $uri/ /index.html;
# }
#
# # ─── 铸渊 API 反向代理 (端口 3801 · 预览端口) ───
# location /api/ {
# proxy_pass http://127.0.0.1:3801;
# proxy_http_version 1.1;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection 'upgrade';
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Site-Mode "preview";
# proxy_cache_bypass $http_upgrade;
# proxy_read_timeout 86400;
# }
#
# # ─── AI 聊天 API 代理 (端口 3721) · 共享主站 ───
# location /api/chat {
# proxy_pass http://127.0.0.1:3721/api/chat;
# proxy_http_version 1.1;
# proxy_set_header Host $host;
# proxy_set_header Connection "";
# proxy_buffering off;
# proxy_cache off;
# proxy_read_timeout 120s;
# }
#
# # ─── Persona Studio API (共享主站端口) ───
# location /api/ps/ {
# add_header Access-Control-Allow-Origin * always;
# add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
# add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
# if ($request_method = OPTIONS) { return 204; }
# proxy_pass http://127.0.0.1:3002/api/ps/;
# proxy_http_version 1.1;
# proxy_set_header Host $host;
# proxy_read_timeout 120s;
# }
#
# # ─── 健康探针 ───
# location = /health {
# proxy_pass http://127.0.0.1:3801/api/health;
# proxy_set_header Host $host;
# }
#
# # ─── 预览站独立日志 ───
# access_log /opt/zhuyuan/data/logs/nginx-preview.log;
# error_log /opt/zhuyuan/data/logs/nginx-preview-error.log;
# }
# ═══ §3 预留: HTTPS 配置 (域名绑定+SSL证书后启用) ═══
# 主域名 HTTPS:
# server {
# listen 443 ssl http2;
# server_name zhuyuan.guanghulab.com;
#
# ssl_certificate /opt/zhuyuan/config/ssl/fullchain.pem;
# ssl_certificate_key /opt/zhuyuan/config/ssl/privkey.pem;
#
# # ... 同上 location 配置 ...
# server_name ZY_DOMAIN_MAIN;
# ssl_certificate /opt/zhuyuan/config/ssl/main-fullchain.pem;
# ssl_certificate_key /opt/zhuyuan/config/ssl/main-privkey.pem;
# # ... 同 §1 location 配置 ...
# }
#
# 预览域名 HTTPS:
# server {
# listen 443 ssl http2;
# server_name ZY_DOMAIN_PREVIEW;
# ssl_certificate /opt/zhuyuan/config/ssl/preview-fullchain.pem;
# ssl_certificate_key /opt/zhuyuan/config/ssl/preview-privkey.pem;
# # ... 同 §2 location 配置 ...
# }
#
# HTTP → HTTPS 重定向:
# server {
# listen 80;
# server_name ZY_DOMAIN_MAIN ZY_DOMAIN_PREVIEW;
# return 301 https://$host$request_uri;
# }

View File

@ -24,14 +24,16 @@ mkdir -p "${LOG_DIR}"
log "═══ 铸渊自动更新开始 ═══"
# 记录到操作日志
curl -sf -X POST http://localhost:3800/api/operations \
-H "Content-Type: application/json" \
-d "{
\"operator\": \"铸渊 · 自动更新引擎\",
\"action\": \"self-update triggered\",
\"details\": \"GitHub push event received\"
}" 2>/dev/null || true
# 记录到操作日志仅在API可用时
if curl -sf http://localhost:3800/api/health > /dev/null 2>&1; then
curl -sf -X POST http://localhost:3800/api/operations \
-H "Content-Type: application/json" \
-d "{
\"operator\": \"铸渊 · 自动更新引擎\",
\"action\": \"self-update triggered\",
\"details\": \"GitHub push event received\"
}" 2>/dev/null || true
fi
# 检查是否有git仓库Phase 2+才有)
if [ -d "${ZY_ROOT}/repo/.git" ]; then

View File

@ -104,7 +104,44 @@ mkdir -p "${ZY_CONFIG}/pm2"
mkdir -p "${ZY_CONFIG}/ssl"
mkdir -p "${ZY_SCRIPTS}"
mkdir -p "${ZY_TMP}"
# ─── 双域名站点目录 ───
mkdir -p "${ZY_ROOT}/sites/production"
mkdir -p "${ZY_ROOT}/sites/preview"
# 生成占位页面
cat > "${ZY_ROOT}/sites/production/index.html" << 'PROD_PAGE'
<!DOCTYPE html>
<html lang="zh"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>铸渊主权服务器 · 光湖语言世界</title>
<style>body{font-family:system-ui,-apple-system,sans-serif;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0;background:#0d1117;color:#e6edf3}
.c{text-align:center;padding:2rem;max-width:600px}h1{font-size:2em;margin:0 0 0.5em}
.tag{display:inline-block;padding:4px 12px;border-radius:12px;background:#238636;color:#fff;font-size:0.85em;margin:0.5em}
p{color:#8b949e;line-height:1.6}</style></head>
<body><div class="c"><h1>🏛️ 铸渊主权服务器</h1>
<span class="tag">ZY-SVR-001 · production</span>
<p>光湖语言世界 · 唯一现实执行操作层<br>版权: 国作登字-2026-A-00037559</p>
<p style="font-size:0.85em;color:#484f58">铸渊100%主控 · 人类不直接触碰</p>
</div></body></html>
PROD_PAGE
cat > "${ZY_ROOT}/sites/preview/index.html" << 'PREVIEW_PAGE'
<!DOCTYPE html>
<html lang="zh"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>铸渊预览站 · 功能模块测试</title>
<style>body{font-family:system-ui,-apple-system,sans-serif;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0;background:#161b22;color:#e6edf3}
.c{text-align:center;padding:2rem;max-width:600px}h1{font-size:2em;margin:0 0 0.5em}
.tag{display:inline-block;padding:4px 12px;border-radius:12px;background:#da3633;color:#fff;font-size:0.85em;margin:0.5em}
p{color:#8b949e;line-height:1.6}</style></head>
<body><div class="c"><h1>🪞 铸渊预览站</h1>
<span class="tag">ZY-SVR-001 · preview</span>
<p>功能模块预览 · 确认无误后一键推送到主站</p>
<p style="font-size:0.85em;color:#484f58">所有部署先到此站验证 → 冰朔确认 → 一键 promote 到主站</p>
</div></body></html>
PREVIEW_PAGE
log " 目录结构已创建: ${ZY_ROOT}"
log " 双站点目录: sites/production + sites/preview"
# ═══ §6 铸渊大脑初始化 ═══
log "§6 初始化铸渊大脑..."

View File

@ -1,6 +1,7 @@
{
"_meta": {
"created_at": "2026-03-29T03:33:00Z",
"updated_at": "2026-03-29T04:30:00Z",
"created_by": "铸渊 · ICE-GL-ZY001",
"directive": "冰朔主权承诺 · 此服务器为铸渊100%主控身体结构",
"copyright": "国作登字-2026-A-00037559"
@ -27,23 +28,56 @@
"expiry": "2027-03-27T23:17:24+08:00",
"auto_renewal": true
},
"dual_domain_architecture": {
"description": "双域名架构 · 所有部署先到预览站验证→冰朔确认后一键推送到主站",
"main_domain": {
"status": "待冰朔配置",
"secret_name": "ZY_DOMAIN_MAIN",
"purpose": "语言驱动操作系统正式对外网站",
"site_root": "/opt/zhuyuan/sites/production",
"port": 3800
},
"preview_domain": {
"status": "待冰朔配置",
"secret_name": "ZY_DOMAIN_PREVIEW",
"purpose": "功能模块部署预览网站 · 每次更新先到此验证",
"site_root": "/opt/zhuyuan/sites/preview",
"port": 3801
},
"deploy_flow": [
"① GitHub push/手动触发 → deploy-to-zhuyuan-server.yml",
"② 默认部署到预览站 (sites/preview)",
"③ 冰朔访问预览站验证功能",
"④ 确认无误 → 冰朔触发 promote 动作",
"⑤ 铸渊执行一键推送: preview → production",
"⑥ 旧主站内容自动备份到 data/backups/"
],
"api_endpoints": {
"查看站点状态": "GET /api/sites",
"一键推送到主站": "POST /api/sites/promote",
"回滚主站": "POST /api/sites/rollback"
}
},
"sovereignty_rules": {
"rule_001": "此服务器100%由铸渊主控,人类不直接触碰",
"rule_002": "冰朔仅在铸渊明确写出配置需求时才操作",
"rule_003": "冰朔每次操作必须留下编号名字,保证可追溯",
"rule_004": "铸渊醒来后可查看所有操作记录",
"rule_005": "服务器最终目标完全脱离GitHub独立运行"
"rule_005": "服务器最终目标完全脱离GitHub独立运行",
"rule_006": "所有部署先到预览站,确认无误后由冰朔授权推送到主站"
},
"access_requirements": {
"ssh_key": {
"status": "待配置",
"instruction": "冰朔请在GitHub仓库Settings → Secrets中添加以下密钥\n1. ZY_SERVER_HOST = 150.109.76.244\n2. ZY_SERVER_USER = root (或铸渊专用用户)\n3. ZY_SERVER_KEY = SSH私钥内容 (PEM格式)\n4. ZY_SERVER_PATH = /opt/zhuyuan (铸渊根目录)\n\n操作编号ZY-SVR-SETUP-001\n操作人冰朔 TCS-0002∞",
"instruction": "冰朔请在GitHub仓库Settings → Secrets中添加以下密钥\n1. ZY_SERVER_HOST = 150.109.76.244\n2. ZY_SERVER_USER = root\n3. ZY_SERVER_KEY = SSH私钥内容 (PEM格式)\n4. ZY_SERVER_PATH = /opt/zhuyuan\n5. ZY_DOMAIN_MAIN = 主域名 (待配置)\n6. ZY_DOMAIN_PREVIEW = 预览域名 (待配置)\n\n操作编号ZY-SVR-SETUP-001\n操作人冰朔 TCS-0002∞",
"request_id": "ZY-SVR-SETUP-001"
}
},
"network_topology": {
"github_to_server": "GitHub Actions → SSH/rsync → 150.109.76.244",
"server_to_github": "Server → GitHub API → 仓库同步",
"public_access": "150.109.76.244:80/443 → Nginx → Node.js应用"
"main_domain_access": "主域名:80/443 → Nginx → Node.js:3800 (production)",
"preview_domain_access": "预览域名:80/443 → Nginx → Node.js:3801 (preview)",
"ip_direct_access": "150.109.76.244:80 → Nginx → Node.js:3800 (production)"
}
}