From 66f93c67f5e7a31b1b325d671edbf45bb0424939 Mon Sep 17 00:00:00 2001 From: zikai <1621362626@qq.com> Date: Mon, 27 Jul 2026 13:52:40 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E6=95=B4=E4=BD=93?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E8=84=9A=E6=9C=AC=E4=B8=8E=E9=83=A8=E7=BD=B2?= =?UTF-8?q?=E6=8C=87=E5=8D=97=EF=BC=88=E7=BB=84=E4=BB=B6=E7=8B=AC=E7=AB=8B?= =?UTF-8?q?/=E6=95=B4=E4=BD=93/=E6=8C=81=E4=B9=85=E5=8C=96=E4=B8=89?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - deploy.sh:整体部署,构建 zMainPage + rsync 到 /var/www/html + 配置 Apache 反代(/api /pdf /pdf-admin /static 等到 zTools2)+ 重启后端 - docs/deployment.md:三种部署模式文档(组件独立开发 / 整体生产 / systemd 持久化) - README:补部署指南链接 --- README.md | 1 + deploy.sh | 107 ++++++++++++++++++++++++++++++++ docs/deployment.md | 148 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 256 insertions(+) create mode 100755 deploy.sh create mode 100644 docs/deployment.md diff --git a/README.md b/README.md index ba738cf..995dd00 100644 --- a/README.md +++ b/README.md @@ -101,4 +101,5 @@ npm run preview # 本地预览构建产物 - [子项目 timeTableFix 管理(submodule 升级 / 移除)](./docs/submodule-timeTableFix.md) - [子项目 z449 管理(submodule + i18n prop 桥接)](./docs/submodule-z449.md) - [子项目 zPDF_package 管理(submodule + iframe 同源集成)](./docs/submodule-zPDF_package.md) +- [部署指南(组件独立 / 整体 / 持久化 systemd)](./docs/deployment.md) - [README 勘误记录](./docs/readme-fixes.md) diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..2aed395 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +# 整体部署:构建并部署 zMainPage(含子模块)+ zTools2(后端)到生产环境。 +# +# 生产拓扑: +# Apache(:80) -> 静态文件 /var/www/html(zMainPage 构建产物) +# -> 反代 /api、/pdf、/pdf-admin、/ws 等到 zTools2(127.0.0.1:6867) +# zTools2(127.0.0.1:6867) -> MySQL(3306) + uploads/ 磁盘 +# +# 前提:zMainPage 与 zTools2 在同一主机(zMainPage 父项目,zTools2 同级目录)。 +# 用法:./deploy.sh [--no-restart] (--no-restart 仅更新文件不重启 zTools2) +set -euo pipefail + +cd "$(dirname "$0")" +ROOT="$(pwd)" +RESTART=1 +[[ "${1:-}" == "--no-restart" ]] && RESTART=0 + +# 兄弟项目路径:zTools2 与 zMainPage 同级 +ZTOOLS2="../zTools2" +ZTOOLS2_DIR="$(cd "$ZTOOLS2" 2>/dev/null && pwd)" || { + echo "未找到 zTools2(期望在 $ZTOOLS2);请确保与 zMainPage 同级目录" >&2 + exit 1 +} + +WEB_ROOT="${WEB_ROOT:-/var/www/html}" + +echo "==> [1/4] 构建 zMainPage(含子模块)" +# 子模块依赖需各自安装(构建期编译其 .vue) +[[ -d third_party/timeTableFix/node_modules ]] || (cd third_party/timeTableFix && npm install) +[[ -d third_party/z449/node_modules ]] || (cd third_party/z449 && npm install) +# zPDF_package 是 iframe 集成,不参与 mainPage 构建,但确保其源码存在 +[[ -d third_party/zPDF_package ]] || git submodule update --init third_party/zPDF_package +npm run build + +echo "==> [2/4] 部署 zMainPage 构建产物到 $WEB_ROOT" +sudo mkdir -p "$WEB_ROOT/js/mainPage" "$WEB_ROOT/css/mainPage" +sudo rsync -a --delete dist/js/mainPage/ "$WEB_ROOT/js/mainPage/" +sudo rsync -a --delete dist/css/mainPage/ "$WEB_ROOT/css/mainPage/" +sudo rsync -a dist/index.html "$WEB_ROOT/index.html" +[[ -f dist/favicon.svg ]] && sudo rsync -a dist/favicon.svg "$WEB_ROOT/favicon.svg" +# SPA 回退 .htaccess(history 模式) +cat > /tmp/zmainpage_htaccess <<'HT' +RewriteEngine On +RewriteCond %{REQUEST_FILENAME} -f [OR] +RewriteCond %{REQUEST_FILENAME} -d +RewriteRule ^ - [L] +RewriteRule ^ index.html [L] +HT +sudo cp /tmp/zmainpage_htaccess "$WEB_ROOT/.htaccess" + +echo "==> [3/4] 配置 Apache 反代(zMainPage -> zTools2)" +# 确保 proxy / rewrite / headers 模块启用 +sudo a2enmod proxy proxy_http rewrite headers >/dev/null 2>&1 || true +# 写入 vhost 配置(仅当不存在时,避免覆盖已有 HTTPS 配置) +VHOST="/etc/apache2/sites-available/zmainpage.conf" +if [[ ! -f "$VHOST" ]]; then + sudo tee "$VHOST" >/dev/null <<'VH' + + DocumentRoot /var/www/html + # zTools2 反代:/api、/pdf、/pdf-admin、/static、/upload、/files、/wb、/ws 等转发到后端 + ProxyPreserveHost On + ProxyPass /api/ http://127.0.0.1:6867/api/ + ProxyPassReverse /api/ http://127.0.0.1:6867/api/ + ProxyPass /pdf http://127.0.0.1:6867/pdf + ProxyPassReverse /pdf http://127.0.0.1:6867/pdf + ProxyPass /pdf-admin http://127.0.0.1:6867/pdf-admin + ProxyPassReverse /pdf-admin http://127.0.0.1:6867/pdf-admin + ProxyPass /static/ http://127.0.0.1:6867/static/ + ProxyPassReverse /static/ http://127.0.0.1:6867/static/ + ProxyPass /upload http://127.0.0.1:6867/upload + ProxyPassReverse /upload http://127.0.0.1:6867/upload + ProxyPass /files http://127.0.0.1:6867/files + ProxyPassReverse /files http://127.0.0.1:6867/files + ProxyPass /wb http://127.0.0.1:6867/wb + ProxyPassReverse /wb http://127.0.0.1:6867/wb + ProxyPass /wb-admin http://127.0.0.1:6867/wb-admin + ProxyPassReverse /wb-admin http://127.0.0.1:6867/wb-admin + ProxyPass /health http://127.0.0.1:6867/health + ProxyPassReverse /health http://127.0.0.1:6867/health + # SPA 回退:非文件非目录的请求回退到 index.html + + AllowOverride All + Require all granted + + +VH + sudo a2dissite 000-default >/dev/null 2>&1 || true + sudo a2ensite zmainpage >/dev/null + echo " 已写入 $VHOST 并启用" +else + echo " $VHOST 已存在,跳过(如需更新请手动编辑)" +fi +sudo systemctl reload apache2 + +echo "==> [4/4] 重启 zTools2 后端" +if [[ $RESTART -eq 1 ]]; then + (cd "$ZTOOLS2_DIR" && ./stop.sh >/dev/null 2>&1 || true) + (cd "$ZTOOLS2_DIR" && ./start.sh) +else + echo " --no-restart:跳过 zTools2 重启" +fi + +echo +echo "部署完成。" +echo " - zMainPage: http://localhost(Apache :80,静态文件 + SPA)" +echo " - zTools2: http://127.0.0.1:6867(经 Apache 反代 /api /pdf 等)" +echo " - PDF 页签: http://localhost/pdf -> iframe 同源嵌入 zTools2 /pdf" diff --git a/docs/deployment.md b/docs/deployment.md new file mode 100644 index 0000000..589a40f --- /dev/null +++ b/docs/deployment.md @@ -0,0 +1,148 @@ +# 部署指南 + +zPDF_package 功能涉及三个项目协同:**zMainPage**(父站,Vue3 静态站)、**zTools2**(后端 API + PDF 页面)、**zPDF_package**(PDF 转换前端源码,zMainPage 子模块)。提供三种部署模式,按需选用。 + +## 拓扑 + +``` +浏览器 -> Apache(:80) + ├── 静态文件 /var/www/html (zMainPage 构建产物:主页 + 页签) + └── 反代 -> zTools2(127.0.0.1:6867) + ├── /api/pdf/* PDF 转换 API(cookie 用户) + ├── /pdf PDF 转换页面(iframe 嵌入源) + ├── /pdf-admin PDF 管理页(Basic Auth) + ├── /static/pdf* 前端静态资源 + └── MySQL(3306) + uploads/ +``` + +PDF 页签 = zMainPage 用 iframe 嵌入 zTools2 的 `/pdf` 页面(同源,cookie 第一方生效)。 + +--- + +## 模式一:组件独立部署(开发/调试) + +各组件独立运行,互不依赖部署,适合开发调试。 + +### 1. zTools2 后端独立运行 + +```bash +cd zTools2 +./setup.sh # 首次:venv + 依赖 + 建库 + SFTP 密钥 +./start.sh # 启动 HTTP(127.0.0.1:6867) + SFTP(2022) +# 或:python -m uvicorn app.main:app --host 127.0.0.1 --port 6867 +``` + +访问:http://127.0.0.1:6867/pdf(PDF 页面)、http://127.0.0.1:6867/docs(API 文档)。 + +### 2. zPDF_package 前端独立运行 + +```bash +cd zPDF_package +npm install +npm run dev # http://localhost:5175 +``` + +`vite.config.js` 已配代理:`/api/pdf/*` 与 `/api/admin/pdf/*` 转发到 `127.0.0.1:6867`(需 zTools2 在跑)。 + +### 3. zMainPage 独立运行 + +```bash +cd zMainPage +git submodule update --init --recursive # 含 timeTableFix / z449 / zPDF_package +npm install +(cd third_party/timeTableFix && npm install) +(cd third_party/z449 && npm install) +npm run dev # http://localhost:5173 +``` + +> 独立模式下 PDF 页签的 iframe 指向 `https://f.zikai.wang/pdf`(线上),如需指向本地 zTools2,改 `src/config/app.config.js` 的 `pdf.baseUrl` 为 `http://127.0.0.1:6867` 后重新 `npm run dev`。 + +--- + +## 模式二:整体部署(生产,一次性) + +一条命令构建并部署全部组件到生产。**前提**:zMainPage 与 zTools2 在同一主机的同级目录。 + +```bash +cd zMainPage +./deploy.sh # 构建 + 部署 + 配置 Apache 反代 + 重启 zTools2 +./deploy.sh --no-restart # 仅更新文件,不重启 zTools2(如 zTools2 由 systemd 管理) +``` + +`deploy.sh` 做的事: +1. 构建 zMainPage(含子模块),rsync 到 `/var/www/html` +2. 写入 `.htaccess`(SPA history 回退) +3. 配置 Apache vhost(`/etc/apache2/sites-available/zmainpage.conf`)反代 `/api` `/pdf` `/pdf-admin` `/static` 等到 `127.0.0.1:6867` +4. 重启 zTools2(除非 `--no-restart`) + +部署后访问 http://localhost/ 即主页,PDF 页签 iframe 同源加载 `/pdf`。 + +> 已有 HTTPS vhost 时:`deploy.sh` 不会覆盖(仅首次写入)。手动在现有 vhost 加 `ProxyPass /pdf http://127.0.0.1:6867/pdf` 等规则即可。 + +--- + +## 模式三:持久化部署(systemd,开机自启 + 崩溃重启) + +zTools2 后端需长期运行(PDF 转换是异步后台任务)。用 systemd 管理实现开机自启与崩溃自动重启。 + +### 安装 systemd 服务 + +```bash +cd zTools2 +./deploy/install-systemd.sh +``` + +脚本自动: +- 用实际路径填充 `deploy/ztools2.service` 模板(自动检测 `.venv/bin/uvicorn` 或系统 `uvicorn`) +- 写入 `/etc/systemd/system/ztools2.service` +- `systemctl enable --now ztools2`(开机自启 + 立即启动) + +### 运维命令 + +```bash +systemctl status ztools2 # 状态 +systemctl restart ztools2 # 重启(更新代码后) +systemctl stop ztools2 # 停止 +journalctl -u ztools2 -f # 实时日志 +``` + +### 卸载 + +```bash +sudo systemctl disable --now ztools2 +sudo rm /etc/systemd/system/ztools2.service +sudo systemctl daemon-reload +``` + +### 与整体部署配合 + +生产推荐:**systemd 管理 zTools2 + deploy.sh 部署前端**。 + +```bash +# 首次 +cd zTools2 && ./setup.sh && ./deploy/install-systemd.sh # 后端持久化 +cd ../zMainPage && ./deploy.sh --no-restart # 前端部署(不重启后端,systemd 管) +# 后续更新前端 +cd zMainPage && ./deploy.sh --no-restart +# 后续更新后端代码 +cd zTools2 && sudo systemctl restart ztools2 +``` + +--- + +## 环境要求 + +| 项 | 要求 | +|----|------| +| OS | Ubuntu 22.04+(systemd + apache2) | +| Python | ≥ 3.10(本仓开发用 3.14,需 SQLAlchemy ≥ 2.0.37) | +| Node.js | ≥ 18 | +| MySQL | 8.x | +| Apache | 2.4(启用 proxy / proxy_http / rewrite / headers) | +| weasyprint 系统库 | libpango-1.0-0 / libpangoft2-1.0-0 / libcairo2 / libgdk-pixbuf-2.0-0 | + +## 防火墙 + +- 80(HTTP)/ 443(HTTPS):对外 +- 6867:仅 loopback(经 Apache 反代,不对外) +- 2022(SFTP):按需对外