官网 初版
This commit is contained in:
529
docs/API.md
Normal file
529
docs/API.md
Normal file
@@ -0,0 +1,529 @@
|
||||
# Nanami API 文档
|
||||
|
||||
所有公开接口均无需认证,供客户端软件直接调用。
|
||||
|
||||
基础 URL: `https://nui.rucky.cn`
|
||||
|
||||
---
|
||||
|
||||
# 一、插件市场 API
|
||||
|
||||
供启动器拉取插件列表、详情、版本和下载。
|
||||
|
||||
---
|
||||
|
||||
## 1.1 获取插件列表
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/addons
|
||||
```
|
||||
|
||||
### 参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| category | string | 否 | 按分类筛选(如 `ui`, `quest`, `combat`, `general`) |
|
||||
| search | string | 否 | 按名称或简介模糊搜索 |
|
||||
| published | string | 否 | 默认 `true` 只返回已发布插件,传 `false` 返回全部 |
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "cxxx001",
|
||||
"name": "Nanami",
|
||||
"slug": "nanami",
|
||||
"summary": "一站式乌龟服插件管理器",
|
||||
"description": "详细描述...",
|
||||
"iconUrl": "/uploads/nanami-icon.png",
|
||||
"category": "general",
|
||||
"published": true,
|
||||
"totalDownloads": 1234,
|
||||
"createdAt": "2026-01-01T00:00:00.000Z",
|
||||
"updatedAt": "2026-03-18T10:00:00.000Z",
|
||||
"releases": [
|
||||
{
|
||||
"id": "rel001",
|
||||
"version": "1.0.0",
|
||||
"isLatest": true
|
||||
}
|
||||
],
|
||||
"_count": {
|
||||
"releases": 3
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 响应字段说明
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| id | string | 插件唯一 ID |
|
||||
| name | string | 插件名称 |
|
||||
| slug | string | 插件标识(URL 友好) |
|
||||
| summary | string | 简短描述 |
|
||||
| description | string | 详细描述(支持长文本) |
|
||||
| iconUrl | string\|null | 图标地址 |
|
||||
| category | string | 分类标签 |
|
||||
| published | boolean | 是否已发布 |
|
||||
| totalDownloads | int | 累计下载次数 |
|
||||
| releases | array | 最新版本信息(仅包含 isLatest=true 的版本) |
|
||||
| _count.releases | int | 版本总数 |
|
||||
|
||||
---
|
||||
|
||||
## 1.2 获取插件详情
|
||||
|
||||
通过 ID 或 slug 获取单个插件的完整信息,包含所有版本和截图。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/addons/{id_or_slug}
|
||||
```
|
||||
|
||||
### 参数
|
||||
|
||||
| 参数 | 说明 |
|
||||
|---|---|
|
||||
| id_or_slug | 插件 ID 或 slug,如 `nanami` |
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "cxxx001",
|
||||
"name": "Nanami",
|
||||
"slug": "nanami",
|
||||
"summary": "一站式乌龟服插件管理器",
|
||||
"description": "详细的 Markdown 描述...",
|
||||
"iconUrl": "/uploads/nanami-icon.png",
|
||||
"category": "general",
|
||||
"published": true,
|
||||
"totalDownloads": 1234,
|
||||
"createdAt": "2026-01-01T00:00:00.000Z",
|
||||
"updatedAt": "2026-03-18T10:00:00.000Z",
|
||||
"releases": [
|
||||
{
|
||||
"id": "rel003",
|
||||
"addonId": "cxxx001",
|
||||
"version": "1.2.0",
|
||||
"changelog": "- 新增XX功能\n- 修复YY问题",
|
||||
"downloadType": "local",
|
||||
"filePath": "uploads/nanami-1.2.0.zip",
|
||||
"externalUrl": null,
|
||||
"gameVersion": "1.12.1",
|
||||
"downloadCount": 500,
|
||||
"isLatest": true,
|
||||
"createdAt": "2026-03-18T10:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "rel002",
|
||||
"addonId": "cxxx001",
|
||||
"version": "1.1.0",
|
||||
"changelog": "- 修复界面问题",
|
||||
"downloadType": "local",
|
||||
"filePath": "uploads/nanami-1.1.0.zip",
|
||||
"externalUrl": null,
|
||||
"gameVersion": "1.12.1",
|
||||
"downloadCount": 300,
|
||||
"isLatest": false,
|
||||
"createdAt": "2026-02-15T10:00:00.000Z"
|
||||
}
|
||||
],
|
||||
"screenshots": [
|
||||
{
|
||||
"id": "ss001",
|
||||
"addonId": "cxxx001",
|
||||
"imageUrl": "/uploads/screenshot1.png",
|
||||
"sortOrder": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 错误响应
|
||||
|
||||
| HTTP 状态码 | 说明 |
|
||||
|---|---|
|
||||
| 404 | 插件不存在 |
|
||||
|
||||
---
|
||||
|
||||
## 1.3 获取版本列表
|
||||
|
||||
获取所有版本,可按插件 ID 筛选。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/releases?addonId={addonId}
|
||||
```
|
||||
|
||||
### 参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| addonId | string | 否 | 按插件 ID 筛选 |
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "rel003",
|
||||
"addonId": "cxxx001",
|
||||
"version": "1.2.0",
|
||||
"changelog": "- 新增XX功能",
|
||||
"downloadType": "local",
|
||||
"filePath": "uploads/nanami-1.2.0.zip",
|
||||
"externalUrl": null,
|
||||
"gameVersion": "1.12.1",
|
||||
"downloadCount": 500,
|
||||
"isLatest": true,
|
||||
"createdAt": "2026-03-18T10:00:00.000Z",
|
||||
"addon": {
|
||||
"id": "cxxx001",
|
||||
"name": "Nanami",
|
||||
"slug": "nanami"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 版本字段说明
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| id | string | 版本唯一 ID |
|
||||
| addonId | string | 所属插件 ID |
|
||||
| version | string | 版本号(如 "1.2.0") |
|
||||
| changelog | string | 更新日志 |
|
||||
| downloadType | string | `local` 本地文件 / `url` 外部链接 |
|
||||
| gameVersion | string | 适配的游戏版本(如 "1.12.1") |
|
||||
| downloadCount | int | 下载次数 |
|
||||
| isLatest | boolean | 是否为最新版本 |
|
||||
| addon | object | 所属插件基本信息 |
|
||||
|
||||
---
|
||||
|
||||
## 1.4 下载插件
|
||||
|
||||
通过版本 ID 下载对应的插件压缩包。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/download/{releaseId}
|
||||
```
|
||||
|
||||
### 行为
|
||||
|
||||
- **本地文件**:返回文件二进制流,`Content-Disposition` 设为 `attachment`
|
||||
- **外部链接**:302 重定向到外部下载地址
|
||||
- 每次调用自动递增版本下载计数和插件总下载计数
|
||||
|
||||
### 响应头(本地文件时)
|
||||
|
||||
```
|
||||
Content-Type: application/octet-stream
|
||||
Content-Disposition: attachment; filename="nanami-1.2.0.zip"
|
||||
Content-Length: 1048576
|
||||
```
|
||||
|
||||
### 错误响应
|
||||
|
||||
| HTTP 状态码 | 说明 |
|
||||
|---|---|
|
||||
| 404 | 版本不存在或文件丢失 |
|
||||
|
||||
---
|
||||
|
||||
# 二、软件更新 API
|
||||
|
||||
供启动器检查自身版本更新和热更新。
|
||||
|
||||
---
|
||||
|
||||
## 软件标识(slug)
|
||||
|
||||
| slug | 用途 | 文件类型 |
|
||||
|---|---|---|
|
||||
| `nanami-launcher` | 启动器全量安装包 | Nanami-Launcher-x.x.x.exe |
|
||||
| `nanami-launcher-patch` | 热更新补丁包 | app.asar |
|
||||
|
||||
---
|
||||
|
||||
## 2.1 检查更新
|
||||
|
||||
客户端启动时调用此接口,传入当前版本号以检测是否有新版本可用。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/software/check-update?slug={slug}&versionCode={versionCode}
|
||||
```
|
||||
|
||||
### 参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| slug | string | 是 | 软件标识 |
|
||||
| versionCode | int | 否 | 当前客户端的版本代码(整数),不传默认为 0 |
|
||||
|
||||
### 响应示例
|
||||
|
||||
**有更新:**
|
||||
|
||||
```json
|
||||
{
|
||||
"hasUpdate": true,
|
||||
"forceUpdate": false,
|
||||
"latest": {
|
||||
"version": "1.2.0",
|
||||
"versionCode": 120,
|
||||
"changelog": "- 新增XX功能\n- 修复YY问题",
|
||||
"downloadUrl": "https://nui.rucky.cn/api/software/download/cxxx123",
|
||||
"fileSize": 5242880,
|
||||
"minVersion": "1.0.0",
|
||||
"createdAt": "2026-03-18T10:00:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**无更新:**
|
||||
|
||||
```json
|
||||
{
|
||||
"hasUpdate": false,
|
||||
"forceUpdate": false,
|
||||
"latest": {
|
||||
"version": "1.0.0",
|
||||
"versionCode": 100,
|
||||
"changelog": "...",
|
||||
"downloadUrl": "https://nui.rucky.cn/api/software/download/cxxx123",
|
||||
"fileSize": 5242880,
|
||||
"minVersion": null,
|
||||
"createdAt": "2026-03-01T10:00:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 响应字段说明
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| hasUpdate | boolean | 是否有新版本 |
|
||||
| forceUpdate | boolean | 是否强制更新(true 时客户端应阻止用户继续使用旧版) |
|
||||
| latest.version | string | 最新版本号(如 "1.2.0") |
|
||||
| latest.versionCode | int | 最新版本代码(整数,用于比较大小) |
|
||||
| latest.changelog | string | 更新日志 |
|
||||
| latest.downloadUrl | string | 下载地址(直接用于下载) |
|
||||
| latest.fileSize | int | 文件大小(字节) |
|
||||
| latest.minVersion | string\|null | 最低兼容版本号 |
|
||||
| latest.createdAt | string | 发布时间 (ISO 8601) |
|
||||
|
||||
### 错误响应
|
||||
|
||||
| HTTP 状态码 | 说明 |
|
||||
|---|---|
|
||||
| 400 | 缺少 slug 参数 |
|
||||
| 404 | 软件不存在或暂无版本 |
|
||||
|
||||
---
|
||||
|
||||
## 2.2 下载软件包
|
||||
|
||||
通过版本 ID 下载对应的软件安装包。一般从"检查更新"接口返回的 `downloadUrl` 直接获取。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/software/download/{versionId}
|
||||
```
|
||||
|
||||
### 行为
|
||||
|
||||
- **本地文件**:返回文件二进制流,`Content-Disposition` 设为 `attachment`
|
||||
- **外部链接**:302 重定向到外部下载地址
|
||||
- 每次调用自动递增下载计数
|
||||
|
||||
### 响应头(本地文件时)
|
||||
|
||||
```
|
||||
Content-Type: application/octet-stream
|
||||
Content-Disposition: attachment; filename="nanami-launcher-v1.2.0.exe"
|
||||
Content-Length: 5242880
|
||||
```
|
||||
|
||||
### 错误响应
|
||||
|
||||
| HTTP 状态码 | 说明 |
|
||||
|---|---|
|
||||
| 404 | 版本不存在或文件丢失 |
|
||||
|
||||
---
|
||||
|
||||
## 2.3 首页启动器最新版本下载
|
||||
|
||||
直接下载 `nanami-launcher` 的最新版本,用于首页下载按钮。
|
||||
|
||||
### 请求
|
||||
|
||||
```
|
||||
GET /api/software/latest
|
||||
```
|
||||
|
||||
下载最新全量包(自动递增下载计数)。
|
||||
|
||||
```
|
||||
GET /api/software/latest?info=1
|
||||
```
|
||||
|
||||
仅返回版本信息 JSON,不下载。
|
||||
|
||||
---
|
||||
|
||||
## 2.4 客户端更新检查流程
|
||||
|
||||
Nanami 启动器在启动后应按以下顺序检查更新:
|
||||
|
||||
```
|
||||
客户端启动(当前 versionCode = 76)
|
||||
│
|
||||
├── 步骤 1: 检查全量更新
|
||||
│ GET /api/software/check-update?slug=nanami-launcher&versionCode=76
|
||||
│ │
|
||||
│ ├── forceUpdate=true → 弹出强制更新对话框,下载完整安装包
|
||||
│ │ 不再检查热更新
|
||||
│ │
|
||||
│ └── hasUpdate=true, forceUpdate=false → 显示"新版本"徽章(用户自行决定)
|
||||
│ │
|
||||
│ └── 继续步骤 2
|
||||
│
|
||||
├── 步骤 2: 检查热更新
|
||||
│ GET /api/software/check-update?slug=nanami-launcher-patch&versionCode=76
|
||||
│ │
|
||||
│ ├── hasUpdate=true → 静默下载 app.asar,替换本地文件
|
||||
│ │ 显示"就绪"徽章,提示重启生效
|
||||
│ │
|
||||
│ └── hasUpdate=false → 当前已是最新,无需操作
|
||||
│
|
||||
└── 正常运行
|
||||
```
|
||||
|
||||
### 版本号对应关系示例
|
||||
|
||||
| 发布类型 | 版本号 | versionCode | slug |
|
||||
|---|---|---|---|
|
||||
| 全量安装包 | 0.7.6 | 76 | nanami-launcher |
|
||||
| 热更新补丁 | 0.7.7 | 77 | nanami-launcher-patch |
|
||||
| 全量大版本 | 0.8.0 | 80 | nanami-launcher |
|
||||
|
||||
### 后台操作
|
||||
|
||||
- **发布全量版本**:在「Nanami 启动器(全量包)」中上传 `.exe` 文件
|
||||
- **发布热更新**:在「Nanami 热更新包」中上传 `app.asar` 文件
|
||||
- 两者的 `versionCode` 应保持递增关系,以便客户端正确比较
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
# 三、客户端集成示例(Electron)
|
||||
|
||||
## 3.1 启动器自身更新
|
||||
|
||||
```javascript
|
||||
const BASE_URL = "https://nui.rucky.cn/api/software/check-update";
|
||||
const CURRENT_VERSION_CODE = 76;
|
||||
|
||||
async function checkUpdates() {
|
||||
// 步骤 1: 检查全量更新
|
||||
const fullResp = await fetch(
|
||||
`${BASE_URL}?slug=nanami-launcher&versionCode=${CURRENT_VERSION_CODE}`
|
||||
);
|
||||
const fullData = await fullResp.json();
|
||||
|
||||
if (fullData.hasUpdate && fullData.forceUpdate) {
|
||||
showForceUpdateDialog(fullData.latest);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fullData.hasUpdate) {
|
||||
showUpdateBadge(fullData.latest);
|
||||
}
|
||||
|
||||
// 步骤 2: 检查热更新
|
||||
const patchResp = await fetch(
|
||||
`${BASE_URL}?slug=nanami-launcher-patch&versionCode=${CURRENT_VERSION_CODE}`
|
||||
);
|
||||
const patchData = await patchResp.json();
|
||||
|
||||
if (patchData.hasUpdate) {
|
||||
const asarResp = await fetch(patchData.latest.downloadUrl);
|
||||
const buffer = await asarResp.arrayBuffer();
|
||||
// 写入本地 app.asar 路径...
|
||||
showRestartBadge();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3.2 插件市场拉取
|
||||
|
||||
```javascript
|
||||
const API_BASE = "https://nui.rucky.cn";
|
||||
|
||||
// 获取全部已发布插件
|
||||
async function fetchAddons(category?: string, search?: string) {
|
||||
const params = new URLSearchParams();
|
||||
if (category) params.set("category", category);
|
||||
if (search) params.set("search", search);
|
||||
|
||||
const resp = await fetch(`${API_BASE}/api/addons?${params}`);
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
// 获取单个插件详情(含所有版本和截图)
|
||||
async function fetchAddonDetail(slug: string) {
|
||||
const resp = await fetch(`${API_BASE}/api/addons/${slug}`);
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
// 下载插件最新版本
|
||||
async function downloadAddon(addon: any) {
|
||||
const latestRelease = addon.releases?.find((r: any) => r.isLatest);
|
||||
if (!latestRelease) return;
|
||||
|
||||
const downloadUrl = `${API_BASE}/api/download/${latestRelease.id}`;
|
||||
const resp = await fetch(downloadUrl);
|
||||
const buffer = await resp.arrayBuffer();
|
||||
// 保存到 WoW 插件目录 Interface/AddOns/...
|
||||
}
|
||||
|
||||
// 检查插件是否有更新(对比本地已安装版本)
|
||||
async function checkAddonUpdates(installedAddons: { slug: string; version: string }[]) {
|
||||
const addons = await fetchAddons();
|
||||
const updates = [];
|
||||
|
||||
for (const installed of installedAddons) {
|
||||
const remote = addons.find((a: any) => a.slug === installed.slug);
|
||||
if (!remote) continue;
|
||||
|
||||
const latestRelease = remote.releases?.[0];
|
||||
if (latestRelease && latestRelease.version !== installed.version) {
|
||||
updates.push({
|
||||
addon: remote,
|
||||
currentVersion: installed.version,
|
||||
newVersion: latestRelease.version,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return updates;
|
||||
}
|
||||
```
|
||||
309
docs/DEPLOY-BAOTA.md
Normal file
309
docs/DEPLOY-BAOTA.md
Normal file
@@ -0,0 +1,309 @@
|
||||
# 阿里云宝塔面板部署文档
|
||||
|
||||
本文档介绍如何在阿里云 ECS + 宝塔面板环境中部署 nanami-web 项目。
|
||||
|
||||
---
|
||||
|
||||
## 方案概览
|
||||
|
||||
```
|
||||
用户浏览器 --> Nginx (宝塔管理,SSL) --> Node.js (PM2 守护) --> PostgreSQL
|
||||
```
|
||||
|
||||
- **Nginx**: 由宝塔面板管理,负责反向代理和 SSL
|
||||
- **Node.js**: 使用 PM2 进程守护运行 Next.js standalone 产物
|
||||
- **PostgreSQL**: 通过宝塔面板安装,或使用 Docker
|
||||
|
||||
---
|
||||
|
||||
## 一、环境准备
|
||||
|
||||
### 1.1 宝塔面板安装软件
|
||||
|
||||
在宝塔面板「软件商店」中安装:
|
||||
|
||||
- **Nginx**(推荐最新稳定版)
|
||||
- **PostgreSQL 16**(或通过 Docker 安装)
|
||||
- **PM2 管理器**(Node.js 进程管理)
|
||||
- **Node.js 版本管理器**,并安装 **Node.js 20+**
|
||||
|
||||
### 1.2 创建数据库
|
||||
|
||||
1. 进入宝塔面板 → 数据库 → PostgreSQL
|
||||
2. 添加数据库:
|
||||
- 数据库名:`nanamiweb`(宝塔不允许包含下划线等特殊字符)
|
||||
- 用户名:`nanami`
|
||||
- 密码:自行设定,建议只用字母和数字(记住用于后续配置)
|
||||
|
||||
如果宝塔不支持 PostgreSQL 管理界面,可通过终端操作:
|
||||
|
||||
```bash
|
||||
# 切换到 postgres 用户
|
||||
sudo -u postgres psql
|
||||
|
||||
# 创建用户和数据库
|
||||
CREATE USER nanami WITH PASSWORD 'your_password_here';
|
||||
CREATE DATABASE nanamiweb OWNER nanami;
|
||||
\q
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、部署项目
|
||||
|
||||
### 2.1 上传代码
|
||||
|
||||
```bash
|
||||
# 在服务器上克隆代码(或通过宝塔面板上传 zip)
|
||||
cd /www/wwwroot
|
||||
git clone <your-repo-url> nanami-web
|
||||
cd nanami-web
|
||||
```
|
||||
|
||||
### 2.2 安装依赖并构建
|
||||
|
||||
```bash
|
||||
# 安装 Node.js 依赖
|
||||
npm install
|
||||
|
||||
# 创建环境变量文件
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
### 2.3 配置环境变量
|
||||
|
||||
编辑 `/www/wwwroot/nanami-web/.env`:
|
||||
|
||||
```env
|
||||
DATABASE_URL="postgresql://nanami:your_password_here@localhost:5432/nanamiweb?schema=public"
|
||||
NEXTAUTH_SECRET="生成一个随机字符串"
|
||||
NEXTAUTH_URL="https://your-domain.com"
|
||||
ADMIN_USERNAME="admin"
|
||||
ADMIN_PASSWORD="your_admin_password"
|
||||
```
|
||||
|
||||
生成随机密钥:
|
||||
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
### 2.4 初始化数据库
|
||||
|
||||
```bash
|
||||
# 推送表结构
|
||||
npx prisma db push
|
||||
|
||||
# 初始化管理员账号
|
||||
npx tsx prisma/seed.ts
|
||||
```
|
||||
|
||||
### 2.5 构建项目
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
构建完成后会在 `.next/standalone` 目录生成独立的 Node.js 应用。
|
||||
|
||||
### 2.6 准备运行目录
|
||||
|
||||
```bash
|
||||
# 复制静态文件到 standalone 目录
|
||||
cp -r .next/static .next/standalone/.next/static
|
||||
cp -r public .next/standalone/public
|
||||
|
||||
# 创建上传目录
|
||||
mkdir -p .next/standalone/uploads
|
||||
|
||||
# 创建软链接使 uploads 共享
|
||||
ln -sf /www/wwwroot/nanami-web/uploads .next/standalone/uploads
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、使用 PM2 启动应用
|
||||
|
||||
### 3.1 创建 PM2 配置文件
|
||||
|
||||
在项目根目录创建 `ecosystem.config.js`:
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: "nanami-web",
|
||||
script: ".next/standalone/server.js",
|
||||
cwd: "/www/wwwroot/nanami-web",
|
||||
env: {
|
||||
NODE_ENV: "production",
|
||||
PORT: 3000,
|
||||
HOSTNAME: "0.0.0.0",
|
||||
},
|
||||
instances: 1,
|
||||
autorestart: true,
|
||||
max_memory_restart: "512M",
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### 3.2 启动应用
|
||||
|
||||
**方式一:通过宝塔 PM2 管理器**
|
||||
|
||||
1. 进入宝塔面板 → 软件商店 → PM2 管理器
|
||||
2. 添加项目:
|
||||
- 项目目录:`/www/wwwroot/nanami-web`
|
||||
- 启动文件:`.next/standalone/server.js`
|
||||
- 项目名称:`nanami-web`
|
||||
|
||||
**方式二:通过命令行**
|
||||
|
||||
```bash
|
||||
cd /www/wwwroot/nanami-web
|
||||
pm2 start ecosystem.config.js
|
||||
pm2 save
|
||||
pm2 startup # 设置开机自启
|
||||
```
|
||||
|
||||
### 3.3 验证应用运行
|
||||
|
||||
```bash
|
||||
curl http://localhost:3000
|
||||
# 应返回 HTML 内容
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、配置 Nginx 反向代理
|
||||
|
||||
### 4.1 宝塔面板创建网站
|
||||
|
||||
1. 进入宝塔面板 → 网站 → 添加站点
|
||||
2. 域名:填写你的域名(如 `addon.example.com`)
|
||||
3. PHP 版本:选择「纯静态」
|
||||
4. 不创建数据库
|
||||
|
||||
### 4.2 配置反向代理
|
||||
|
||||
进入网站设置 → 反向代理 → 添加反向代理:
|
||||
|
||||
- 代理名称:`nanami`
|
||||
- 目标 URL:`http://127.0.0.1:3000`
|
||||
- 发送域名:`$host`
|
||||
|
||||
或手动编辑 Nginx 配置,在 `server` 块中添加:
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
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_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# 上传文件大小限制(根据需要调整)
|
||||
client_max_body_size 100m;
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 配置 SSL
|
||||
|
||||
1. 进入网站设置 → SSL
|
||||
2. 选择 Let's Encrypt → 申请证书
|
||||
3. 开启「强制 HTTPS」
|
||||
|
||||
### 4.4 阿里云安全组
|
||||
|
||||
确保阿里云安全组放行以下端口:
|
||||
|
||||
| 端口 | 用途 |
|
||||
|---|---|
|
||||
| 80 | HTTP |
|
||||
| 443 | HTTPS |
|
||||
| 22 | SSH |
|
||||
|
||||
> 注意:3000 端口**不需要**对外开放,Nginx 通过内部代理访问。
|
||||
|
||||
---
|
||||
|
||||
## 五、更新部署
|
||||
|
||||
当代码有更新时:
|
||||
|
||||
```bash
|
||||
cd /www/wwwroot/nanami-web
|
||||
|
||||
# 拉取最新代码
|
||||
git pull
|
||||
|
||||
# 安装依赖(如有新依赖)
|
||||
npm install
|
||||
|
||||
# 同步数据库变更(如有 schema 变化)
|
||||
npx prisma db push
|
||||
|
||||
# 重新构建
|
||||
npm run build
|
||||
|
||||
# 复制静态文件
|
||||
cp -r .next/static .next/standalone/.next/static
|
||||
cp -r public .next/standalone/public
|
||||
ln -sf /www/wwwroot/nanami-web/uploads .next/standalone/uploads
|
||||
|
||||
# 重启应用
|
||||
pm2 restart nanami-web
|
||||
```
|
||||
|
||||
可以将上述步骤写成脚本 `deploy.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
cd /www/wwwroot/nanami-web
|
||||
git pull
|
||||
npm install
|
||||
npx prisma db push
|
||||
npm run build
|
||||
cp -r .next/static .next/standalone/.next/static
|
||||
cp -r public .next/standalone/public
|
||||
ln -sf /www/wwwroot/nanami-web/uploads .next/standalone/uploads
|
||||
pm2 restart nanami-web
|
||||
echo "部署完成"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、常见问题
|
||||
|
||||
### Q: 上传的文件在哪里?
|
||||
|
||||
上传的文件存储在 `/www/wwwroot/nanami-web/uploads/` 目录。请确保定期备份。
|
||||
|
||||
### Q: 如何备份数据库?
|
||||
|
||||
```bash
|
||||
pg_dump -U nanami nanami_web > backup_$(date +%Y%m%d).sql
|
||||
```
|
||||
|
||||
可在宝塔面板的「计划任务」中添加定时备份。
|
||||
|
||||
### Q: 忘记管理员密码?
|
||||
|
||||
重新运行 seed 脚本(会用 .env 中的密码重置):
|
||||
|
||||
```bash
|
||||
cd /www/wwwroot/nanami-web
|
||||
npx tsx prisma/seed.ts
|
||||
```
|
||||
|
||||
### Q: 如何查看应用日志?
|
||||
|
||||
```bash
|
||||
pm2 logs nanami-web
|
||||
pm2 logs nanami-web --lines 100 # 查看最近100行
|
||||
```
|
||||
Reference in New Issue
Block a user