# 知命阁(zhimingge)Ubuntu 部署文档 > 仓库:[https://git.bz121.com/dekun/zhimingge.git](https://git.bz121.com/dekun/zhimingge.git) 本文档说明在 **Ubuntu 服务器**上使用 **root 用户**、**PM2** 将知命阁部署到 **`/opt/zhimingge`** 的完整流程。 --- ## 1. 部署架构 ``` ┌─────────────────┐ 用户浏览器 ──→ │ Nginx (可选) │ :80 / :443 │ 反向代理 │ └────────┬────────┘ │ ┌────────▼────────┐ │ PM2 │ │ zhimingge │ :3130 └────────┬────────┘ │ ┌────────▼────────┐ │ Next.js │ │ standalone │ │ /opt/zhimingge │ └─────────────────┘ │ ┌────────▼────────┐ │ op.bz121.com │ AI API │ /v1 │ └─────────────────┘ ``` | 组件 | 说明 | |------|------| | 操作系统 | Ubuntu 20.04 / 22.04 / 24.04 LTS | | 运行用户 | root(按需求) | | 安装目录 | `/opt/zhimingge` | | 进程管理 | PM2 | | 构建模式 | Next.js `output: "standalone"` | | 默认端口 | **3130** | --- ## 2. 服务器要求 | 项目 | 最低配置 | 推荐配置 | |------|----------|----------| | CPU | 1 核 | 2 核 | | 内存 | 1 GB | 2 GB+ | | 磁盘 | 2 GB | 10 GB | | 网络 | 可访问 git.bz121.com、op.bz121.com | — | --- ## 3. 一次性环境准备 以 **root** 登录服务器后执行: ### 3.1 更新系统 ```bash apt update && apt upgrade -y ``` ### 3.2 安装 Node.js 20(推荐 LTS) ```bash curl -fsSL https://deb.nodesource.com/setup_20.x | bash - apt install -y nodejs node -v # 应 >= v20 npm -v ``` ### 3.3 安装 pnpm 与 PM2 ```bash npm install -g pnpm pm2 pnpm -v pm2 -v ``` ### 3.4 安装 Git ```bash apt install -y git ``` ### 3.5(可选)安装 Nginx 反向代理 若需域名 + HTTPS,建议安装 Nginx 与 Certbot: ```bash apt install -y nginx certbot python3-certbot-nginx ``` --- ## 4. 克隆与目录 ```bash mkdir -p /opt cd /opt # 首次克隆(私有仓库需配置凭据,见第 5 节) git clone https://git.bz121.com/dekun/zhimingge.git zhimingge cd /opt/zhimingge ``` 最终目录: ``` /opt/zhimingge/ ├── app/ ├── content/ ├── ecosystem.config.cjs ├── .env.local ← 生产环境变量(勿提交 Git) ├── package.json └── ... ``` --- ## 5. Git 凭据(私有仓库) 仓库 [dekun/zhimingge](https://git.bz121.com/dekun/zhimingge.git) 为私有仓库,克隆前需配置认证。 ### 方式 A:HTTPS + 访问令牌(推荐) ```bash git config --global credential.helper store git clone https://git.bz121.com/dekun/zhimingge.git /opt/zhimingge # 按提示输入 Gitea 用户名与 Personal Access Token ``` 在 Gitea 生成 Token:用户设置 → Applications → Generate New Token(勾选 `repo` 权限)。 ### 方式 B:SSH ```bash ssh-keygen -t ed25519 -C "zhimingge-deploy" -f /root/.ssh/zhimingge -N "" cat /root/.ssh/zhimingge.pub # 将公钥添加到 Gitea → Settings → SSH Keys cat >> /root/.ssh/config << 'EOF' Host git.bz121.com IdentityFile /root/.ssh/zhimingge StrictHostKeyChecking accept-new EOF git clone git@git.bz121.com:dekun/zhimingge.git /opt/zhimingge ``` --- ## 6. 环境变量 ```bash cd /opt/zhimingge cp .env.example .env.local nano .env.local ``` **`.env.local` 示例:** ```env # AI 接口(必填) OPENAI_API_KEY=你的密钥 # AI 地址与模型(已有默认值,可按需覆盖) OPENAI_BASE_URL=https://op.bz121.com/v1 OPENAI_MODEL=huihui_ai/gemma-4-abliterated:e4b # 服务端口(与 PM2 ecosystem.config.cjs 一致) PORT=3130 NODE_ENV=production ``` 保存后限制权限: ```bash chmod 600 .env.local ``` --- ## 7. 构建与启动 ### 7.1 安装依赖 ```bash cd /opt/zhimingge pnpm install --frozen-lockfile ``` ### 7.2 生产构建 ```bash pnpm run build ``` 构建成功后生成 `.next/standalone/` 独立运行包。 ### 7.3 复制静态资源(standalone 必需) Next.js standalone 模式需手动链接静态文件: ```bash cd /opt/zhimingge # 复制 static 与 public 到 standalone 目录 cp -r .next/static .next/standalone/.next/static cp -r public .next/standalone/public # 复制内容库(服务端读取卦辞 Markdown) cp -r content .next/standalone/content ``` > **说明**:若应用从项目根目录读取 `content/`,PM2 的 `cwd` 应设为 `/opt/zhimingge` 而非 standalone 子目录。当前 `ecosystem.config.cjs` 使用项目根目录 + `pnpm start`,构建后也可改用 standalone 的 `server.js`(见 7.5 备选方案)。 ### 7.4 使用 PM2 启动(推荐方式) 项目根目录已包含 `ecosystem.config.cjs`: ```bash cd /opt/zhimingge pm2 start ecosystem.config.cjs pm2 save pm2 startup # 按 PM2 提示执行生成的命令,确保开机自启 ``` 常用 PM2 命令: ```bash pm2 status # 查看状态 pm2 logs zhimingge # 查看日志 pm2 restart zhimingge # 重启 pm2 stop zhimingge # 停止 pm2 delete zhimingge # 删除进程 ``` ### 7.5 备选:standalone 直接运行 若希望仅运行 standalone 产物(体积更小): ```bash cd /opt/zhimingge/.next/standalone PORT=3130 node server.js ``` 对应 PM2 配置片段: ```javascript { name: "zhimingge", cwd: "/opt/zhimingge/.next/standalone", script: "server.js", env: { PORT: 3130, NODE_ENV: "production", }, } ``` 此时需确保 `content/`、`public/` 路径在代码中相对于 `cwd` 可访问。 ### 7.6 验证 ```bash curl -I http://127.0.0.1:3130 # 应返回 HTTP/1.1 200 ``` 浏览器访问:`http://服务器IP:3130` --- ## 8. Nginx 反向代理(可选) 假设域名为 `zhimingge.example.com`: ```bash nano /etc/nginx/sites-available/zhimingge ``` ```nginx server { listen 80; server_name zhimingge.example.com; location / { proxy_pass http://127.0.0.1:3130; 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-Forwarded-Proto $scheme; proxy_cache_bypass $http_upgrade; # AI 流式响应需禁用缓冲 proxy_buffering off; proxy_read_timeout 300s; } } ``` ```bash ln -s /etc/nginx/sites-available/zhimingge /etc/nginx/sites-enabled/ nginx -t systemctl reload nginx # HTTPS(Let's Encrypt) certbot --nginx -d zhimingge.example.com ``` --- ## 9. 更新部署流程 代码推送至 Gitea 后,在服务器执行: ```bash cd /opt/zhimingge # 拉取最新代码 git pull origin main # 安装新依赖(如有变更) pnpm install --frozen-lockfile # 重新构建 pnpm run build # 若使用 standalone 复制方式,重新复制 static/public/content cp -r .next/static .next/standalone/.next/static cp -r public .next/standalone/public cp -r content .next/standalone/content # 重启 pm2 restart zhimingge ``` 可写入脚本 `/opt/zhimingge/scripts/deploy.sh` 一键执行(见项目内脚本)。 --- ## 10. 防火墙 若使用 UFW: ```bash # 仅 Nginx 对外(推荐) ufw allow 22 ufw allow 80 ufw allow 443 ufw enable # 若不用 Nginx,直接暴露 3130 ufw allow 3130 ``` --- ## 11. 日志与排错 ### PM2 日志 ```bash pm2 logs zhimingge --lines 100 ``` 日志文件位置(默认): ``` /root/.pm2/logs/zhimingge-out.log /root/.pm2/logs/zhimingge-error.log ``` ### 常见问题 | 现象 | 可能原因 | 处理 | |------|----------|------| | 502 Bad Gateway | PM2 进程未运行 | `pm2 restart zhimingge` | | AI 解读失败 | API Key 错误或模型名不对 | 检查 `.env.local` | | 卦辞读取失败 | `content/` 路径不存在 | 确认 `content/zhouyi/docs/` 存在 | | 构建 OOM | 内存不足 | 增加 swap 或升级内存 | | 流式输出中断 | Nginx 缓冲 | 设置 `proxy_buffering off` | | Git pull 失败 | 凭据过期 | 重新配置 Token 或 SSH | ### 构建内存不足时增加 Swap ```bash fallocate -l 2G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile echo '/swapfile none swap sw 0 0' >> /etc/fstab ``` ### 测试 AI 接口 ```bash curl https://op.bz121.com/v1/models \ -H "Authorization: Bearer 你的OPENAI_API_KEY" ``` 确认返回列表中包含 `huihui_ai/gemma-4-abliterated:e4b`。 --- ## 12. 安全建议 虽然当前按 **root** 部署,仍建议: 1. **`.env.local` 权限** 设为 `600`,勿提交 Git 2. **API Key** 仅保存在服务器,不要写入前端代码 3. 生产环境使用 **Nginx + HTTPS** 4. 定期 `apt update` 与 `pnpm update` 5. 若后续改为非 root 运行,创建专用用户: ```bash useradd -r -s /bin/false zhimingge chown -R zhimingge:zhimingge /opt/zhimingge # PM2 中以 zhimingge 用户启动 ``` --- ## 13. 快速命令参考 ```bash # 完整首次部署 cd /opt && git clone https://git.bz121.com/dekun/zhimingge.git zhimingge cd /opt/zhimingge cp .env.example .env.local && nano .env.local pnpm install --frozen-lockfile pnpm run build pm2 start ecosystem.config.cjs pm2 save && pm2 startup # 日常更新 cd /opt/zhimingge && git pull && pnpm install && pnpm run build && pm2 restart zhimingge # 查看状态 pm2 status && curl -I http://127.0.0.1:3130 ``` --- ## 14. 相关文档 - 产品说明:[docs/SPEC.md](./SPEC.md) - 环境变量示例:[../.env.example](../.env.example) - PM2 配置:[../ecosystem.config.cjs](../ecosystem.config.cjs)