Files
opendance-web/tasks/010-deploy.md
T
zijunchiang 8c76b0a599 feat(web): 移除 Docker 与反代部署,改为 Linux 业务服务并自带管理端托管
需求变更:Web 端只保留业务需求,反向代理交由另外的服务处理,
本项目仅提供 IIS / nginx 反代说明文档,不部署反代。

主要改动:
- web-server: 新增管理端静态托管(ADMIN_DIR、SPA 深链接回退),
  反代因此只需一条全匹配转发规则;新增 adminDir 配置项
- deploy/install.sh: 删除 nginx 安装与站点配置逻辑,改为原生 Linux
  服务部署(systemd → OpenRC → SysVinit → 后台进程四级降级),
  打印反代交接指引
- deploy/ctl.sh: 启停/状态/日志脚本
- deploy/proxy/: 新增反代说明文档(README.md、nginx.conf.example、
  web.config.example),标注上传上限与超时必须同步调整
- 删除 deploy/nginx/、web-server/admin/nginx.conf、Dockerfile、
  docker-compose.yml、.dockerignore
- scripts/package-release.sh: 锚定排除规则 + 产物完整性校验
- 文档同步:README.txt、DSH.md、project.yaml、tasks/008、tasks/010
2026-09-15 01:25:19 +08:00

136 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# T-WEB-010 部署(Linux 原生站点,不使用 Docker)
- **状态**:done(需求变更后重做)
- **依赖**:T-WEB-001 ~ 009
## 目标
Web 服务端以一**个 Linux 站点**的形式部署运行:nginx 托管管理端静态站点并反向代理
API,Node 进程由 systemd 托管。**不使用 Docker**,**不部署 MySQL**(数据库为部署方
提供的现有实例)。
> **需求变更记录**:初版按文档 §4.4 实现为 Docker Compose。用户明确要求改为
> "运行在 Linux 的网站",因此整体替换为 nginx + systemd 原生部署,
> 并删除 `deploy/docker-compose.yml`、`web-server/Dockerfile`、
> `web-server/admin/Dockerfile`。
## load
```
DSH.md
contracts/database.md
deploy/install.sh
deploy/uninstall.sh
deploy/.env.example
deploy/systemd/opendance-api.service
deploy/proxy/README.md
```
## 部署形态
**职责边界**:本端只提供**业务服务**;反向代理由另外的服务/团队负责。
```
浏览器 ──▶ 反向代理(外部提供,IIS / nginx / 网关…)
│ 整体转发,不需要托管静态文件
▼
Node 业务服务 :3000
├── / 管理端页面(本服务自带,含 SPA 深链接回退)
├── /assets/ 前端静态资源
├── /api/ REST API
├── /health 健康检查
├── /static/ 上传文件
└── /contracts/ 契约快照
│
▼
现有 MySQL / MariaDB 实例
```
本服务同时提供 API 与管理端页面(`ADMIN_DIR`),因此反代**只需一条全匹配转发规则**,
既不用在代理层托管静态文件,也不用配置 SPA 回退。
`deploy/install.sh` **不安装、不配置任何反向代理软件**。
## 交付物
| 文件 | 说明 |
|---|---|
| `deploy/install.sh` | 一键部署:前置检查 → 建用户/目录 → 装依赖 → 迁移 → systemd → nginx → 健康检查 |
| `deploy/uninstall.sh` | 卸载;默认保留上传数据,`--purge` 才删除 |
| `deploy/.env.example` | 部署环境变量样例(含 `HOST=127.0.0.1`) |
| `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` | 管理端容器内配置(保留给需要独立静态托管的场景) |
## 进程管理:四层降级
"运行在 Linux 上"不应等于"必须有 systemd"。安装时按以下顺序探测并选择:
```
1. systemd /run/systemd/system 存在且 systemctl 可用
2. OpenRC rc-service + rc-update 可用
3. SysVinit /etc/init.d 存在且 update-rc.d 或 chkconfig 可用
4. 都没有 nohup 后台进程 + PID 文件(deploy/ctl.sh)
并写 crontab @reboot 实现开机自启
```
三种 init 方式最终都调用同一个 Node 进程,只是守护方式不同;第 4 种由
`deploy/ctl.sh` 提供 start/stop/restart/status/logs。
**不使用 sudo**:脚本已要求 root,降权到服务用户用 `runuser → setpriv → su`
依次回退(部分服务器根本没装 sudo)。
## 关键实现
- **Node 进程只监听 `127.0.0.1`**(`HOST=127.0.0.1`),外部只能经 nginx 访问;
对应新增配置项 `AppConfig.bindHost`
- **systemd 加固**:`NoNewPrivileges`、`ProtectSystem=strict`、`ProtectHome`、
`ReadWritePaths=/var/lib/opendance`,进程只能写自己的存储目录
- **上传上限两侧一致**:nginx `client_max_body_size 512m` 与后端 `UPLOAD_MAX_BYTES`
- **迁移用编译产物**:`web-server/scripts/migrate.mjs` 检测到 `dist/` 时走
`typeorm -d dist/db/data-source.js`,无需在服务器上装 devDependencies
- **`/contracts/` 静态暴露**:另两端可直接从站点取契约快照
- 安装脚本自动移除 nginx 默认站点,避免其抢占 80 端口
## 验收
```bash
cp deploy/.env.example deploy/.env # 填写 DB_*
sudo bash deploy/install.sh
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/` |
| 不部署、不管理 MySQL | ✅ 部署脚本不含任何数据库安装/建库操作 |
| 不使用 Docker | ✅ 仓库内已无 Dockerfile / docker-compose / Docker 引用 |
> **环境限制说明**:本次执行环境**无 root 权限**(无法安装 systemd 服务与 nginx
> 站点配置),宿主机也**未安装 nginx**。因此 `deploy/install.sh` 的完整链路
> (systemd 注册 + nginx 重载)未能在本机实机跑通。已完成的等价验证:
> - 后端以 `HOST=127.0.0.1 node dist/main.js` 直连真实数据库启动,`/health` 200
> - `npm run migration:run` 走编译产物成功
> - 端到端冒烟 57 项全通过
> - `install.sh` / `uninstall.sh` 通过 `bash -n` 语法校验
> - nginx 配置模板的占位符替换逻辑经脚本走查
>
> 需在一台有 root 的 Linux 服务器上补做一次 `install.sh` 实机验收。
## 发布产物
```bash
./scripts/package-release.sh
# → dist-release/opendance-web-v0.1.0.tar.gz
```
内容:`web-server/`(源码 + dist)、`admin/`(构建产物)、`deploy/`、
`contracts/` 快照、`THIRD_PARTY.md`、`README.txt`。