需求变更:Web 服务端不再使用 Docker,改为直接运行在 Linux 上的网站。 - 移除 deploy/docker-compose.yml、web-server/Dockerfile、 web-server/admin/Dockerfile、web-server/.dockerignore - 新增 deploy/install.sh:建服务用户与目录 → 装运行期依赖 → 迁移 → 注册 systemd 服务 → 配置 nginx 站点 → 健康检查,一键完成 - 新增 deploy/systemd/opendance-api.service:ProtectSystem=strict 等 安全加固,ReadWritePaths 限定为上传目录 - 新增 deploy/nginx/opendance.conf:同站点托管管理端静态资源 + 反代 /api /health /static,client_max_body_size 512m,SPA 回退 - 新增 deploy/uninstall.sh:默认保留数据,--purge 才删除 - 新增配置项 HOST(AppConfig.bindHost):原生部署下 Node 只监听 127.0.0.1,不直接对外暴露,实测外部 IP 不可达 - 同步更新 contracts/rest-api.yaml、DSH.md、project.yaml、README.txt、 tasks/008、tasks/010 与发布打包脚本
4.7 KiB
4.7 KiB
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/nginx/opendance.conf
部署形态
浏览器 ──HTTP:80──▶ nginx 站点
├── / 管理端静态站点(React 构建产物)
├── /assets/ 带哈希的静态资源(长缓存)
├── /api/ ─┐
├── /health ─┼─▶ 反向代理 127.0.0.1:3000
└── /static/─┘ │
▼
systemd: opendance-api
(Node 进程,仅监听本机)
│
▼
现有 MySQL / MariaDB 实例
交付物
| 文件 | 说明 |
|---|---|
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/nginx/opendance.conf |
站点配置:SPA 回退、API 反代、上传上限 512 MiB、gzip |
web-server/admin/nginx.conf |
管理端容器内配置(保留给需要独立静态托管的场景) |
关键实现
- 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 端口
验收
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直连真实数据库启动,/health200npm run migration:run走编译产物成功- 端到端冒烟 57 项全通过
install.sh/uninstall.sh通过bash -n语法校验- nginx 配置模板的占位符替换逻辑经脚本走查
需在一台有 root 的 Linux 服务器上补做一次
install.sh实机验收。
发布产物
./scripts/package-release.sh
# → dist-release/opendance-web-v0.1.0.tar.gz
内容:web-server/(源码 + dist)、admin/(构建产物)、deploy/、
contracts/ 快照、THIRD_PARTY.md、README.txt。