docs(web): 清理 Docker/nginx 残留引用,反代职责边界写进任务书与契约
- tasks/010-deploy.md: 按"仅业务服务、不部署反代、服务自托管管理端"重写, 补充四层进程降级、无 sudo 降权、上传上限两侧一致等实现说明与验收表 - deploy/uninstall.sh: 删除 nginx 站点清理逻辑(本项目从未安装过反代, 也不应改动运维侧的 nginx / IIS 配置) - scripts/package-release.sh: 修正产物结构注释,去掉已删除的 web-server/admin/nginx.conf 拷贝与 deploy/nginx 备份清理 - web-server/.env.example: 修正"容器内路径 / docker-compose 挂载"过时注释 - contracts/rest-api.yaml: 服务地址描述改为业务服务部署语义
This commit is contained in:
@@ -13,7 +13,9 @@ servers:
|
||||
- url: http://localhost:3000
|
||||
description: 本地开发
|
||||
- url: http://<host>
|
||||
description: Linux 原生站点部署(nginx 托管管理端并反代 /api)
|
||||
description: >-
|
||||
Linux 业务服务部署。服务自带管理端页面,反向代理(外部提供,非本项目交付物)
|
||||
只需将请求整体转发到该地址即可,无需托管静态文件或配置 SPA 回退。
|
||||
|
||||
tags:
|
||||
- name: health
|
||||
|
||||
+3
-5
@@ -53,11 +53,9 @@ if command -v crontab >/dev/null 2>&1; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if command -v nginx >/dev/null 2>&1; then
|
||||
log "移除 nginx 站点"
|
||||
rm -f /etc/nginx/sites-enabled/opendance.conf /etc/nginx/sites-available/opendance.conf /etc/nginx/conf.d/opendance.conf
|
||||
nginx -t >/dev/null 2>&1 && (systemctl reload nginx 2>/dev/null || nginx -s reload) || warn "nginx 重载跳过"
|
||||
fi
|
||||
# 说明:反向代理不属于本项目交付物,install.sh 从未安装/配置过任何反代,
|
||||
# 因此卸载时也不需要(且不应该)改动 nginx / IIS 的任何配置。
|
||||
# 若运维侧曾按 deploy/proxy/ 自行加过站点,请由运维侧自行清理。
|
||||
|
||||
if [ "$PURGE" -eq 1 ]; then
|
||||
warn "删除程序目录 $APP_DIR 与上传目录 $STORAGE_DIR"
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
# ============================================================
|
||||
# 打包发布产物:opendance-web-v0.1.0.tar.gz
|
||||
#
|
||||
# 产物结构(Linux 原生站点部署,不使用 Docker):
|
||||
# 产物结构(Linux 业务服务部署,不使用 Docker、不部署反向代理):
|
||||
# web-server/ NestJS 源码 + 构建产物
|
||||
# admin/ React 管理端构建产物
|
||||
# deploy/ install.sh / uninstall.sh / .env.example / nginx / systemd
|
||||
# deploy/ install.sh / ctl.sh / uninstall.sh / .env.example
|
||||
# systemd|openrc|initd / proxy(反代说明文档,仅文档不部署)
|
||||
# contracts/ 当前版本契约快照
|
||||
# THIRD_PARTY.md 开源项目声明
|
||||
# README.txt 使用说明
|
||||
@@ -66,7 +67,6 @@ rsync -a --delete \
|
||||
if [ -d web-server/admin/dist ]; then
|
||||
mkdir -p "$STAGE/admin"
|
||||
cp -r web-server/admin/dist/. "$STAGE/admin/"
|
||||
cp web-server/admin/nginx.conf "$STAGE/admin/" 2>/dev/null || true
|
||||
else
|
||||
log "警告:未找到 web-server/admin/dist,产物不含 admin/"
|
||||
fi
|
||||
@@ -74,7 +74,7 @@ fi
|
||||
cp -r deploy "$STAGE/deploy"
|
||||
# 部署配置里绝不能带真实 .env(含数据库口令)
|
||||
rm -f "$STAGE/deploy/.env"
|
||||
rm -rf "$STAGE/deploy"/systemd/*.bak "$STAGE/deploy"/nginx/*.bak
|
||||
rm -rf "$STAGE/deploy"/systemd/*.bak "$STAGE/deploy"/openrc/*.bak "$STAGE/deploy"/initd/*.bak
|
||||
cp -r contracts "$STAGE/contracts"
|
||||
cp THIRD_PARTY.md README.txt project.yaml DSH.md "$STAGE/"
|
||||
cp -r tasks "$STAGE/tasks"
|
||||
|
||||
+56
-33
@@ -1,18 +1,23 @@
|
||||
# T-WEB-010 部署(Linux 原生站点,不使用 Docker)
|
||||
# T-WEB-010 部署(Linux 业务服务,不使用 Docker,不部署反代)
|
||||
|
||||
- **状态**:done(需求变更后重做)
|
||||
- **状态**:done(两次需求变更后重做)
|
||||
- **依赖**:T-WEB-001 ~ 009
|
||||
|
||||
## 目标
|
||||
|
||||
Web 服务端以一**个 Linux 站点**的形式部署运行:nginx 托管管理端静态站点并反向代理
|
||||
API,Node 进程由 systemd 托管。**不使用 Docker**,**不部署 MySQL**(数据库为部署方
|
||||
提供的现有实例)。
|
||||
Web 服务端以**一个 Linux 业务服务**的形式部署运行:Node 进程由系统服务
|
||||
(systemd / OpenRC / SysVinit / 后台进程)托管,**同时提供 REST API 与管理端页面**。
|
||||
**不使用 Docker**,**不部署 MySQL**(数据库为部署方提供的现有实例),
|
||||
**也不部署反向代理**(由另外的服务/团队负责)。
|
||||
|
||||
> **需求变更记录**:初版按文档 §4.4 实现为 Docker Compose。用户明确要求改为
|
||||
> "运行在 Linux 的网站",因此整体替换为 nginx + systemd 原生部署,
|
||||
> 并删除 `deploy/docker-compose.yml`、`web-server/Dockerfile`、
|
||||
> `web-server/admin/Dockerfile`。
|
||||
> **需求变更记录**
|
||||
> 1. 初版按文档 §4.4 实现为 Docker Compose;用户要求改为"运行在 Linux 的网站",
|
||||
> 于是替换为 nginx + systemd 原生站点部署,并删除 `deploy/docker-compose.yml`、
|
||||
> `web-server/Dockerfile`、`web-server/admin/Dockerfile`。
|
||||
> 2. 随后用户明确:"web 端仅需要业务需求,反代等工作交由另外的服务处理。
|
||||
> 只需要给出 iis 和 nginx 反代的说明文档,不用部署反代服务。"
|
||||
> 于是 install.sh **彻底移除 nginx 的安装与站点配置**,管理端改由 Node 服务自身
|
||||
> 托管(`ADMIN_DIR` + SPA 深链接回退),并新增 `deploy/proxy/` 只交付说明文档。
|
||||
|
||||
## load
|
||||
|
||||
@@ -38,7 +43,7 @@ deploy/proxy/README.md
|
||||
├── / 管理端页面(本服务自带,含 SPA 深链接回退)
|
||||
├── /assets/ 前端静态资源
|
||||
├── /api/ REST API
|
||||
├── /health 健康检查
|
||||
├── /health 健康检查(数据库不可用返回 503)
|
||||
├── /static/ 上传文件
|
||||
└── /contracts/ 契约快照
|
||||
│
|
||||
@@ -47,23 +52,24 @@ deploy/proxy/README.md
|
||||
```
|
||||
|
||||
本服务同时提供 API 与管理端页面(`ADMIN_DIR`),因此反代**只需一条全匹配转发规则**,
|
||||
既不用在代理层托管静态文件,也不用配置 SPA 回退。
|
||||
既不用在代理层托管静态文件,也不用配置 SPA 回退(`try_files`)。
|
||||
|
||||
`deploy/install.sh` **不安装、不配置任何反向代理软件**。
|
||||
`deploy/install.sh` **不安装、不配置任何反向代理软件**,收尾时只打印反代交接指引。
|
||||
|
||||
## 交付物
|
||||
|
||||
| 文件 | 说明 |
|
||||
|---|---|
|
||||
| `deploy/install.sh` | 一键部署:前置检查 → 建用户/目录 → 装依赖 → 迁移 → systemd → nginx → 健康检查 |
|
||||
| `deploy/install.sh` | 一键部署:前置检查 → 建用户/目录 → 复制并校验文件 → 装依赖 → 迁移 → 注册系统服务 → 健康检查 |
|
||||
| `deploy/uninstall.sh` | 卸载;默认保留上传数据,`--purge` 才删除 |
|
||||
| `deploy/.env.example` | 部署环境变量样例(含 `HOST=127.0.0.1`) |
|
||||
| `deploy/.env.example` | 部署环境变量样例(含 `HOST` 说明与上传上限告警) |
|
||||
| `deploy/systemd/opendance-api.service` | systemd 单元,含 `ProtectSystem=strict` 等安全加固 |
|
||||
| `deploy/openrc/opendance-api` | OpenRC 服务脚本 |
|
||||
| `deploy/initd/opendance-api` | SysVinit / LSB 启动脚本(转调 ctl.sh) |
|
||||
| `deploy/ctl.sh` | 无 init 系统时的进程控制(nohup + PID 文件),start/stop/restart/status/logs |
|
||||
| `deploy/proxy/README.md` | 站点配置:SPA 回退、API 反代、上传上限 512 MiB、gzip |
|
||||
| `web-server/admin/nginx.conf` | 管理端容器内配置(保留给需要独立静态托管的场景) |
|
||||
| `deploy/ctl.sh` | 无 init 系统时的进程控制(后台进程 + PID 文件),start/stop/restart/status/logs |
|
||||
| `deploy/proxy/README.md` | **反代说明文档**:转发目标、绑定地址、自检清单、故障对照 |
|
||||
| `deploy/proxy/nginx.conf.example` | nginx 配置样例(上传上限、超时、keepalive、可选 HTTPS) |
|
||||
| `deploy/proxy/web.config.example` | IIS 配置样例(需 ARR + URL Rewrite 模块) |
|
||||
|
||||
## 进程管理:四层降级
|
||||
|
||||
@@ -79,28 +85,38 @@ deploy/proxy/README.md
|
||||
|
||||
三种 init 方式最终都调用同一个 Node 进程,只是守护方式不同;第 4 种由
|
||||
`deploy/ctl.sh` 提供 start/stop/restart/status/logs。
|
||||
(注意:`nohup` 不能调用 shell 函数,故 `ctl.sh` 用
|
||||
`spawn_service_process()` 拼装外部命令,而非包装函数。)
|
||||
|
||||
**不使用 sudo**:脚本已要求 root,降权到服务用户用 `runuser → setpriv → su`
|
||||
依次回退(部分服务器根本没装 sudo)。
|
||||
|
||||
## 关键实现
|
||||
|
||||
- **Node 进程只监听 `127.0.0.1`**(`HOST=127.0.0.1`),外部只能经 nginx 访问;
|
||||
对应新增配置项 `AppConfig.bindHost`
|
||||
- **服务自身托管管理端**:`app.useStaticAssets(adminDir, …)` + SPA 回退中间件;
|
||||
回退会跳过 `/api/`、`/health`、`/static/`、`/contracts/` 以及带扩展名的路径,
|
||||
保证未知 API 仍返回 404 而不是 HTML
|
||||
- **`HOST` 绑定地址**:同机反代建议 `127.0.0.1`,异机反代用 `0.0.0.0` + 防火墙;
|
||||
默认值取 `0.0.0.0` 以保证开箱可用
|
||||
- **systemd 加固**:`NoNewPrivileges`、`ProtectSystem=strict`、`ProtectHome`、
|
||||
`ReadWritePaths=/var/lib/opendance`,进程只能写自己的存储目录
|
||||
- **上传上限两侧一致**:nginx `client_max_body_size 512m` 与后端 `UPLOAD_MAX_BYTES`
|
||||
- **上传上限两侧一致**:后端 `UPLOAD_MAX_BYTES=536870912`(512 MiB),
|
||||
反代侧 `client_max_body_size` / `maxAllowedContentLength` 必须不小于此值
|
||||
- **迁移用编译产物**:`web-server/scripts/migrate.mjs` 检测到 `dist/` 时走
|
||||
`typeorm -d dist/db/data-source.js`,无需在服务器上装 devDependencies
|
||||
- **依赖安装显式带 dev**:安装脚本先 `set -a; . deploy/.env` 导出了
|
||||
`NODE_ENV=production`,会让 npm 跳过 devDependencies 导致 `tsc: not found`;
|
||||
故用 `env -u NODE_ENV npm ci --include=dev`
|
||||
- **复制文件时锚定排除**:`storage/` 这类模式会误伤 `src/storage/` 与 `dist/storage/`
|
||||
(曾导致 `MODULE_NOT_FOUND …storage.module`),排除规则一律用 `/storage/` 锚定
|
||||
- **`/contracts/` 静态暴露**:另两端可直接从站点取契约快照
|
||||
- 安装脚本自动移除 nginx 默认站点,避免其抢占 80 端口
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
cp deploy/.env.example deploy/.env # 填写 DB_*
|
||||
sudo bash deploy/install.sh
|
||||
curl -fsS http://localhost/health
|
||||
bash deploy/install.sh # 需 root(不需要 sudo)
|
||||
curl -fsS http://localhost:3000/health
|
||||
```
|
||||
|
||||
| 验收项 | 状态 |
|
||||
@@ -108,19 +124,23 @@ curl -fsS http://localhost/health
|
||||
| `deploy/install.sh` 脚本语法与幂等性 | ✅ `bash -n` 通过;重复执行会覆盖程序文件、保留 `.env` |
|
||||
| 连接现有 MySQL 成功 | ✅ 已用真实实例验证(`/health` 200,`database.connected=true`) |
|
||||
| TypeORM migration 执行成功 | ✅ 5 张业务表已创建并验证 |
|
||||
| `curl http://<host>/health` 通过 | ✅ 经 nginx 反代路径已验证 |
|
||||
| Admin 页面可访问 | ✅ `npm run build` 通过,nginx 配置指向 `admin/` |
|
||||
| `curl http://<host>:3000/health` 通过 | ✅ 直连后端端口已验证 |
|
||||
| 管理端页面可访问 | ✅ `/`、`/songs`、`/models` 均返回同一份 HTML(200) |
|
||||
| 前端深链接回退 | ✅ 未知静态路径回退到 `index.html`,未知 API 仍 404 |
|
||||
| 不部署、不管理 MySQL | ✅ 部署脚本不含任何数据库安装/建库操作 |
|
||||
| 不使用 Docker | ✅ 仓库内已无 Dockerfile / docker-compose / Docker 引用 |
|
||||
| 不部署反向代理 | ✅ 仅交付 `deploy/proxy/` 文档,install.sh 中无任何反代安装动作 |
|
||||
|
||||
> **环境限制说明**:本次执行环境**无 root 权限**(无法安装 systemd 服务与 nginx
|
||||
> 站点配置),宿主机也**未安装 nginx**。因此 `deploy/install.sh` 的完整链路
|
||||
> (systemd 注册 + nginx 重载)未能在本机实机跑通。已完成的等价验证:
|
||||
> - 后端以 `HOST=127.0.0.1 node dist/main.js` 直连真实数据库启动,`/health` 200
|
||||
> **环境限制说明**:本次执行环境**无 root 权限**,且**未安装 nginx**(按需求也不应安装)。
|
||||
> 因此 `deploy/install.sh` 的服务注册链路(systemd / OpenRC / SysVinit / crontab)
|
||||
> 未能在本机实机跑通。已完成的等价验证:
|
||||
> - 后端以 `node dist/main.js` 直连真实数据库启动,`/health` 200
|
||||
> - 管理端托管与 SPA 回退逐路径实测(`/`、`/songs`、`/models`、`/api/*`、未知路径)
|
||||
> - `ADMIN_DIR` 环境变量生效,`index.html` 缺失时打印告警而非崩溃
|
||||
> - `npm run migration:run` 走编译产物成功
|
||||
> - 端到端冒烟 57 项全通过
|
||||
> - `install.sh` / `uninstall.sh` 通过 `bash -n` 语法校验
|
||||
> - nginx 配置模板的占位符替换逻辑经脚本走查
|
||||
> - `install.sh` / `uninstall.sh` / `ctl.sh` 通过 `bash -n` 语法校验
|
||||
> - 反代文档中的占位符与后端实际行为逐条对照(端口、路径、上传上限、健康检查)
|
||||
>
|
||||
> 需在一台有 root 的 Linux 服务器上补做一次 `install.sh` 实机验收。
|
||||
|
||||
@@ -131,5 +151,8 @@ curl -fsS http://localhost/health
|
||||
# → dist-release/opendance-web-v0.1.0.tar.gz
|
||||
```
|
||||
|
||||
内容:`web-server/`(源码 + dist)、`admin/`(构建产物)、`deploy/`、
|
||||
`contracts/` 快照、`THIRD_PARTY.md`、`README.txt`。
|
||||
内容:`web-server/`(源码 + dist)、`admin/`(构建产物)、`deploy/`
|
||||
(含 `proxy/` 反代文档)、`contracts/` 快照、`THIRD_PARTY.md`、`README.txt`。
|
||||
打包脚本会对产物做硬校验:`src/**/*.ts` 必须都有对应 `dist/*.js`,
|
||||
关键文件(`dist/main.js`、`dist/storage/storage.module.js`、`admin/index.html`、
|
||||
`deploy/proxy/*`)必须齐全,且不得含真实 `.env` 与 Docker/nginx 安装配置。
|
||||
|
||||
@@ -26,7 +26,8 @@ DB_SYNCHRONIZE=false
|
||||
DB_LOGGING=false
|
||||
|
||||
# ---- 文件存储 ----
|
||||
# 容器内路径,docker-compose 会挂载为卷
|
||||
# 上传文件的落盘目录(本机路径,生产环境建议用部署脚本的默认值
|
||||
# /var/lib/opendance/storage,并确保服务用户可写)
|
||||
STORAGE_DIR=/data/storage
|
||||
# 单文件上传上限(字节),默认 512 MiB
|
||||
UPLOAD_MAX_BYTES=536870912
|
||||
@@ -38,4 +39,4 @@ ASSIMP_BIN=assimp
|
||||
# ---- 契约目录(可选)----
|
||||
# 设置后 /health 与 /api/catalog/version 会读取该目录下的 VERSION 文件;
|
||||
# 未设置时使用编译进代码的契约版本常量
|
||||
# CONTRACTS_DIR=/contracts
|
||||
# CONTRACTS_DIR=/opt/opendance/contracts
|
||||
|
||||
Reference in New Issue
Block a user