# FranklinWH Toolbox 全量部署文档 本文档描述如何在一台**全新的 Ubuntu 服务器**上,从零部署 FranklinWH Toolbox (Vue 3 前端 + Go 后端)的完整流程,包括所有依赖数据库的安装、配置、建库建表、 反向代理与 systemd 服务。安装方式与版本参照当前生产服务器的实际部署。 > 参考环境(当前服务器实测):Ubuntu 22.04.5 LTS,Go 1.26,Node 22.15,pnpm 8.6, > PostgreSQL 14,MongoDB 8.0,Redis 7.4,MinIO(RELEASE 版),Caddy 2.11。 --- ## ⚑ 部署前需要你确认/填写的清单(TODO) 下面列出**必须由你确认或填写**的项。脚本与 `config.env.example` 中对应位置均已用 `# TODO:` 注释标出,可搜索 `TODO` 快速定位。 > 📋 完整的可勾选清单(含填写项与部署步骤)见 [CHECKLIST.md](./CHECKLIST.md)。 **必填(不改则无法正常运行 / 有安全风险)** - [ ] **PostgreSQL 业务口令** `fwh_toolbox` 角色密码:`init_databases.sh` 的 `PG_FWH_PASSWORD` 与 `config.env` 的 `POSTGRES_DSN` 中 `password=` 必须一致。 - [ ] **MinIO 管理员口令** `MINIO_ROOT_USER/MINIO_ROOT_PASSWORD`(勿用默认 `minioadmin`)。 - [ ] **MinIO 业务密钥** `config.env` 的 `MINIO_ACCESS_KEY/MINIO_SECRET_KEY`。 - [ ] **FWH 生产账号** `config.env` 的 `FWH_USER/FWH_PASSWORD`。 - [ ] **FWH MQTT 证书** 放入 `server/cert/pro/`,并核对 `config.env` 中路径。 - [ ] **Casdoor 数据库口令** `CASDOOR_PG_PASSWORD`(勿用默认 `casdoor`)。 - [ ] **Casdoor 应用信息** 在 Casdoor 建 `organization_franklinwh_toolbox` / `app-franklinwh-toolbox`,若新建应用需把 clientId/secret/证书同步到源码 (`service/utils/casdoor/casdoor.go`、`src/utils/casdoor/casdoor.ts`)后重新构建。 - [ ] **域名** 反向代理 Caddyfile 中的 `你的域名`、Casdoor `origin/回调 URL`。 - [ ] **Caddy DNS 凭据** `LIBDNS_SPACESHIP_APIKEY/APISECRET`(spaceship DNS-01 签证书用, 写入 systemd 服务,勿提交仓库)。 - [ ] **远端 MySQL** `config.env` 的 `MYSQL_DSN`(用到站点信息查询功能时必填)。 **需确认(有默认值,请核对是否符合你的环境)** - [ ] 部署根目录 `DEPLOY_ROOT`(默认 `/var/www/fwh-toolbox`)与运行用户 `RUN_USER`。 - [ ] 端口:后端 `APP_PORT=8301`、Asynqmon `8302`、MinIO `9198/9199`、Casdoor `8010`。 - [ ] `APP_ENV`(pro/dev)、`MONGO_DSN` 库名(生产 `FwhToolboxDb`)、`MINIO_BUCKET_NAME`。 - [ ] `KIRO_RUN_AS_USER`/`KIRO_HOME` 改成目标机实际用户。 **可选(用到对应功能才填)** - [ ] FWH 测试环境账号与 MQTT(`FWH_TEST_*`)。 - [ ] Plane 集成(`PLANE_*`)。 > 交互式脚本 `deploy/scripts/setup.sh` 会逐项提示你填写以上内容,推荐优先使用。 --- ## 目录 0. [快速开始:交互式一键部署](#0-快速开始交互式一键部署) 1. [架构总览](#1-架构总览) 2. [端口与目录约定](#2-端口与目录约定) 3. [基础环境与依赖安装](#3-基础环境与依赖安装) 4. [数据库安装](#4-数据库安装) 5. [数据库初始化与数据表导入](#5-数据库初始化与数据表导入) 6. [后端配置](#6-后端配置) 7. [构建与部署后端](#7-构建与部署后端) 8. [构建与部署前端](#8-构建与部署前端) 9. [反向代理(Caddy)](#9-反向代理caddy) 10. [Casdoor 认证服务安装与配置](#10-casdoor-认证服务安装与配置) 11. [启动、验证与排错](#11-启动验证与排错) 12. [附录:一键脚本清单](#12-附录一键脚本清单) --- ## 0. 快速开始:交互式一键部署 如果只想尽快完成部署,直接运行部署入口 `deploy/start.sh`(它会拉起交互式向导 `deploy/scripts/setup.sh`)。向导会**分步引导**你选择/填写内容,并支持**本地**与 **远程(SSH)**两种目标: ```bash cd deploy chmod +x start.sh ./start.sh ``` `start.sh` 会显示一个菜单:既可选「全流程一键部署」,也可只跑某个**单项功能** (依赖 / 初始化 DB / MinIO 账号 / pgAdmin4 / Casdoor / Caddy / Kiro CLI / 构建部署前后端)。 **无论全流程还是单项,都同样支持本地与远程(进入后会先询问 local/remote)。** 单项也可用命令行直达(跳过菜单),本质是给向导传 `--only`: ```bash ./start.sh --only caddy # 只部署 Caddy ./start.sh --only deps,initdb # 只装依赖 + 初始化数据库 ./start.sh --only deploy # 只构建部署前后端(再选前端/后端/两者) ./start.sh --help # 查看全部可选项 ``` > 可选项:`deps casdoor initdb minioacct pgadmin caddy kiro deploy`。 > 单项模式仍会询问该步骤所需的参数(如 Caddy 的域名/DNS token)。 向导流程: 1. **选择模式**:本地 (local) 或 远程 (remote,通过 SSH) 2. **选择步骤**:初始化数据库 / 部署后端 / 部署前端(可自由勾选;`--only` 时跳过此步) 3. **(远程)填写 SSH 连接**:主机、端口、用户、私钥,并自动测试连通性 4. **填写配置**:部署目录、运行用户、PostgreSQL/Mongo/Redis/MinIO/MySQL 等 5. 自动**生成 config.env** → 本机**构建**前端 dist 与后端二进制 → (远程时)**打包上传** → 执行所选步骤 设计要点: - **本地构建 + 远程安装**:前端/后端在运行脚本的机器上构建,再上传到远程, 因此**远程主机无需安装 Go/Node**。 - 脚本**只做建库建表、MinIO 建桶建账号与服务部署**,不自动安装数据库引擎;数据库软件的 安装仍请参考下文第 3、4 章(可在目标机预先装好 PostgreSQL/MongoDB/Redis/MinIO)。 - 反向代理(Caddy)需按第 9 章手动配置。 > 想了解每一步的底层动作、或需要单独执行某一环节,请继续阅读后续章节; > `setup.sh` 内部即是对第 5~8 章操作的编排。 --- ## 1. 架构总览 ``` ┌─────────────────────────────────────────┐ 浏览器 ── HTTPS ────▶ │ Caddy (反向代理, :80/:443) │ │ /fwh-toolbox/* → 前端静态 (:8300) │ │ /fwh-toolbox/api/* → 后端 API (:8301) │ └───────────────┬─────────────────────────┘ │ ┌───────────────────────────────┼──────────────────────────────┐ ▼ ▼ ▼ ┌───────────────┐ ┌────────────────────┐ ┌──────────────────┐ │ 前端静态文件 │ │ Go 后端 │ │ fwh-mcp-server │ │ Apache :8300 │ │ fwh-toolbox-server │ │ (MCP,可选) │ │ /var/www/... │ │ localhost:8301 │ └──────────────────┘ └───────────────┘ │ Asynqmon :8302 │ └─────────┬──────────┘ │ ┌──────────────┬───────────────────┼───────────────┬────────────────┐ ▼ ▼ ▼ ▼ ▼ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────────┐ │PostgreSQL│ │ MongoDB │ │ Redis │ │ MinIO │ │ 远端 MySQL(只读) │ │ :5432 │ │ :27017 │ │ :6379 │ │ :9198 │ │ FWH 生产库 │ │ 本地 │ │ 本地 │ │ 本地 │ │ 本地 │ │ 远程 34.x:3308 │ └─────────┘ └──────────┘ └──────────┘ └──────────┘ └─────────────────┘ ``` 数据库职责说明: | 数据库 | 位置 | 用途 | | --- | --- | --- | | **PostgreSQL** | 本地 | 保存站点原始数据(`original` schema,运行时按雪花ID动态建表)与告警快照(`alarm_snapshot` schema,两张固定表) | | **MongoDB** | 本地 | 保存业务文档数据,集合首次写入时自动创建(生产库 `FwhToolboxDb`) | | **Redis** | 本地 | 缓存 + Asynq 异步任务队列(任务使用 DB 12) | | **MinIO** | 本地 | 对象存储(快照/日志/故障录波等文件),bucket `fwh-toolbox` | | **MySQL** | 远程只读 | FranklinWH 生产库 `home_energy_storage_server`,仅查询站点信息(`iot_gateway` 表)。**新服务器无需安装 MySQL**,只需网络可达并在 `config.env` 配置只读账号 | > 注:后端代码中 MySQL 初始化默认被注释(见 `service/database/database.go`), > 是否启用取决于所用功能;PostgreSQL 与 MongoDB 为必需。 --- ## 2. 端口与目录约定 | 组件 | 端口 | 绑定 | 备注 | | --- | --- | --- | --- | | 后端 API | 8301 | 127.0.0.1 | `APP_PORT`,仅本机,经反代对外 | | Asynqmon | 8302 | 0.0.0.0 | `ASYNQMON_PORT`,任务监控面板 `/asynqmon` | | 前端静态 | 8300 | 由 Web 服务器(Apache/Nginx)托管 dist 目录 | | PostgreSQL | 5432 | 本地 | | | MongoDB | 27017 | 127.0.0.1 | | | Redis | 6379 | 127.0.0.1 | | | MinIO API | 9198 | 本地 | S3 API | | MinIO 控制台 | 9199 | 本地 | Web 控制台 | | Caddy | 80 / 443 | 对外 | 反向代理入口 | 部署目录(与线上一致): ``` /var/www/fwh-toolbox/ ├── fwh-toolbox/ # 前端构建产物(dist/* 拷贝到此) └── server/ # 后端运行目录 ├── fwh-toolbox-server # 后端主程序二进制 ├── fwh-mcp-server # MCP 服务二进制(可选) ├── config.env # 后端配置(由 config.env.example 复制修改) └── cert/ # FWH MQTT 证书 (pro/ 与 test/) ``` --- ## 3. 基础环境与依赖安装 以下命令在全新 Ubuntu 22.04 上以具备 `sudo` 权限的用户执行。 ### 3.1 系统更新与基础工具 ```bash sudo apt update && sudo apt upgrade -y sudo apt install -y curl wget git build-essential ca-certificates gnupg lsb-release ``` ### 3.2 Go 1.26 参照线上使用官方二进制安装(不使用 apt 版本,避免过旧): ```bash GO_VERSION=1.26.4 wget https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz sudo rm -rf /usr/local/go sudo tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz echo 'export PATH=$PATH:/usr/local/go/bin' | sudo tee /etc/profile.d/go.sh source /etc/profile.d/go.sh go version # 期望输出 go version go1.26.x linux/amd64 ``` ### 3.3 Node.js 22 + pnpm ```bash # Node 22 (NodeSource) curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt install -y nodejs node -v # v22.x # pnpm(项目使用 pnpm,lock 文件为 pnpm-lock.yaml) sudo npm install -g pnpm@8 pnpm -v # 8.x ``` ### 3.4 uv(Python 包/工具管理器,可选) 后端 AI 对话 / MCP 相关能力可能通过 `uvx` 拉起基于 Python 的 MCP server,需要 `uv`。 `install_deps.sh` 会自动检测并安装(缺失时),也可手动安装: ```bash # 官方脚本,安装到 /usr/local/bin(全局可用,不修改 shell profile) curl -LsSf https://astral.sh/uv/install.sh \ | sudo env UV_INSTALL_DIR=/usr/local/bin sh -s -- --no-modify-path uv --version # 期望输出 uv 0.x.x ``` --- ## 4. 数据库安装 > **自动检测/安装**:可直接用 `deploy/scripts/install_deps.sh` 一次性完成本章 > 各数据库引擎的检测与(缺失时)安装(幂等,可重复运行): > > ```bash > cd deploy/scripts && chmod +x install_deps.sh > DETECT_ONLY=1 ./install_deps.sh # 仅检测各组件是否已安装 > MINIO_ROOT_USER='admin' MINIO_ROOT_PASSWORD='强密码' \ > ./install_deps.sh postgres mongo redis minio mc docker # 检测并安装缺失项 > ``` > > 下面各小节是等价的手动步骤与版本参考(与线上一致)。 ### 4.1 PostgreSQL 14 ```bash sudo apt install -y postgresql postgresql-contrib sudo systemctl enable --now postgresql psql --version # PostgreSQL 14.x ``` ### 4.2 MongoDB 8.0 Ubuntu 官方仓库没有 MongoDB,使用官方源: ```bash curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | \ sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/8.0 multiverse" | \ sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list sudo apt update sudo apt install -y mongodb-org sudo systemctl enable --now mongod mongosh --eval 'db.runCommand({ping:1})' ``` > 线上 MongoDB 绑定 `127.0.0.1:27017`。如需限制,编辑 `/etc/mongod.conf` 的 > `net.bindIp: 127.0.0.1`。 ### 4.3 Redis 7.x ```bash sudo apt install -y redis-server sudo systemctl enable --now redis-server redis-cli ping # PONG ``` > 后端将 Asynq 任务队列放在 Redis **DB 12**,无需额外配置。 ### 4.4 MinIO(对象存储) 参照线上使用官方二进制 + 独立 `minio-user` + systemd: ```bash # 1. 下载二进制 sudo wget -O /usr/local/bin/minio https://dl.min.io/server/minio/release/linux-amd64/minio sudo chmod +x /usr/local/bin/minio # 2. 创建运行用户与数据目录 sudo useradd -r minio-user -s /sbin/nologin || true sudo mkdir -p /var/lib/minio/data sudo chown -R minio-user:minio-user /var/lib/minio # 3. 环境变量文件 sudo tee /etc/default/minio > /dev/null <<'EOF' MINIO_VOLUMES="/var/lib/minio/data" # API :9198,控制台 :9199(与线上一致) MINIO_OPTS="--address :9198 --console-address :9199" MINIO_ROOT_USER="CHANGE_ME_ADMIN" MINIO_ROOT_PASSWORD="CHANGE_ME_STRONG_PASSWORD" EOF # 4. systemd 服务 sudo tee /etc/systemd/system/minio.service > /dev/null <<'EOF' [Unit] Description=MinIO Documentation=https://docs.min.io Wants=network-online.target After=network-online.target AssertFileIsExecutable=/usr/local/bin/minio [Service] Type=notify WorkingDirectory=/usr/local User=minio-user Group=minio-user EnvironmentFile=-/etc/default/minio ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES Restart=always LimitNOFILE=1048576 TasksMax=infinity OOMScoreAdjust=-1000 [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable --now minio ``` 安装 `mc`(MinIO Client,用于建 bucket): ```bash sudo wget -O /usr/local/bin/mc https://dl.min.io/client/mc/release/linux-amd64/mc sudo chmod +x /usr/local/bin/mc ``` #### 4.4.1 账号与权限模型 MinIO 采用「一个管理员 + 两个业务账号」的划分,业务账号最小权限、按桶名前缀授权: | 账号 | 用途 | 对 `fwh-toolbox*` 桶 | 对 `fwh-toolbox-ai*` 桶 | 对其余桶 | |------|------|----------------------|-------------------------|----------| | `MINIO_ROOT_USER`(root) | 建桶 / 建用户 / 设策略(全局管理) | 全权 | 全权 | 全权 | | `fwh-toolbox` | **后端主服务**(`config.env`) | 读写(含删除) | 读写(含删除)※ | 只读 | | `fwh-toolbox-ai` | **MCP Server**(`config.mcp.env`) | 只读 | 读写(含删除) | 只读 | > ※ `fwh-toolbox-ai-file` 同时匹配 `fwh-toolbox*` 与 `fwh-toolbox-ai*` 两个前缀, > 因此后端账号 `fwh-toolbox` 对 AI 桶也有写权限——这是前缀通配策略的必然结果。 > MCP 工具本身仅做只读访问(`list/read object`),只读权限即可满足。 两个业务账号由脚本 `deploy/scripts/provision_minio.sh` 用 root 通过 `mc admin` 创建(建桶 → 建策略 → 建用户 → 绑定策略,均幂等): ```bash MINIO_ROOT_USER='admin' MINIO_ROOT_PASSWORD='强密码' \ MINIO_SECRET_KEY='业务强密码' MINIO_AI_SECRET_KEY='AI强密码' \ ./deploy/scripts/provision_minio.sh ``` 对应关系(务必一致): - 后端 `config.env` 的 `MINIO_ACCESS_KEY/MINIO_SECRET_KEY` = `provision_minio.sh` 的 `MINIO_ACCESS_KEY/MINIO_SECRET_KEY`(默认 `fwh-toolbox`); - MCP `config.mcp.env` 的 `MINIO_ACCESS_KEY/MINIO_SECRET_KEY` = `provision_minio.sh` 的 `MINIO_AI_ACCESS_KEY/MINIO_AI_SECRET_KEY`(默认账号=密码=`fwh-toolbox-ai`)。 > `setup.sh` 会分别生成 `config.env`(后端)与 `config.mcp.env`(MCP)两份配置, > MCP 那份的 MinIO 凭据默认使用 `fwh-toolbox-ai`。 ### 4.5 远端 MySQL **新服务器不需要安装 MySQL**。它连接的是 FranklinWH 的远程生产库 (示例 `34.211.183.235:3308` 的 `home_energy_storage_server`),只需: - 保证服务器网络能访问该地址与端口; - 在 `config.env` 的 `MYSQL_DSN` 中填入只读账号。 仓库中 `service/database/sql/home_energy_storage_server_iot_gateway_2025-08-11_152722.sql` 是该远程库 `iot_gateway` 表的结构快照,仅供参考/本地测试导入使用。 --- ## 5. 数据库初始化与数据表导入 ### 5.1 PostgreSQL:建角色 / 建库 / 建 schema / 建表 后端的 `alarm_snapshot` 两张表**不会**自动迁移,需要预先创建;`original` schema 下的原始数据表在运行时按雪花ID动态创建,因此只需建好 schema。仓库提供了幂等 SQL: `deploy/sql/init_pgsql.sql` 一键执行(推荐使用脚本,见下节);或手动: ```bash # 使用自定义密码执行;不传则默认 fwh_toolbox(仅限本地开发) # 密码直接传入、无需加引号(脚本内部用 %L 安全转义) sudo -u postgres psql -v ON_ERROR_STOP=1 \ -v fwh_pwd=你的强密码 \ -f deploy/sql/init_pgsql.sql ``` 执行后将得到: - 角色 `fwh_toolbox`(可登录) - 数据库 `fwh_toolbox_db`(owner=`fwh_toolbox`) - schema:`original`、`alarm_snapshot`、`public` - 表:`alarm_snapshot.site_alarm_snapshot_data`、 `alarm_snapshot.site_alarm_snapshot_file_record` 验证: ```bash sudo -u postgres psql -d fwh_toolbox_db -c "\dn" sudo -u postgres psql -d fwh_toolbox_db -c "\dt alarm_snapshot.*" ``` ### 5.2 一键初始化所有本地数据库 仓库提供 `deploy/scripts/init_databases.sh`,完成 PostgreSQL 初始化与 MongoDB/Redis 连通性检查(**不涉及 MinIO**): ```bash cd deploy/scripts chmod +x init_databases.sh PG_FWH_PASSWORD='你的强密码' \ ./init_databases.sh ``` > MinIO 的建桶、业务账号与最小权限策略**全部**由下面的 `provision_minio.sh` > 负责,`init_databases.sh` 不再处理 MinIO。 #### 5.2.1 创建 MinIO 业务账号与策略 见 4.4.1 的账号模型。用 root 账户运行(幂等:建桶 → 建策略 → 建用户 → 绑定): ```bash cd deploy/scripts chmod +x provision_minio.sh MINIO_ROOT_USER='你的MinIO管理员' MINIO_ROOT_PASSWORD='你的MinIO密码' \ MINIO_SECRET_KEY='业务账号强密码' \ MINIO_AI_SECRET_KEY='AI账号强密码' \ ./provision_minio.sh ``` 完成后确保:`config.env` 用 `fwh-toolbox`(`MINIO_ACCESS_KEY/SECRET_KEY`), `config.mcp.env` 用 `fwh-toolbox-ai`(默认账号=密码=`fwh-toolbox-ai`)。 ### 5.3 MongoDB 无需手动建集合——集合会在后端首次写入时自动创建。生产环境使用库名 `FwhToolboxDb`(在 `MONGO_DSN` 末尾指定)。若要从旧库迁移数据: ```bash # 导出(旧服务器) mongodump --uri="mongodb://127.0.0.1:27017/FwhToolboxDb" --out=/tmp/fwhdump # 导入(新服务器) mongorestore --uri="mongodb://127.0.0.1:27017" /tmp/fwhdump ``` ### 5.4 迁移已有 PostgreSQL 业务数据(可选) 若需把旧服务器的完整业务数据搬到新服务器: ```bash # 旧服务器导出(含 original 动态表 + alarm_snapshot 表) sudo -u postgres pg_dump -Fc -d fwh_toolbox_db -f /tmp/fwh_toolbox_db.dump # 新服务器恢复(先用 init_pgsql.sql 建好角色/库,再恢复) sudo -u postgres pg_restore -d fwh_toolbox_db --no-owner --role=fwh_toolbox /tmp/fwh_toolbox_db.dump ``` --- ## 6. 后端配置 后端使用 Viper 读取配置,优先级:`./.env` → `./config.env`,环境变量可覆盖。 仓库提供模板 `deploy/config.env.example`。 ```bash # 复制模板到 service 目录(本地运行)或直接到部署目录 /var/www/fwh-toolbox/server/ cp deploy/config.env.example service/config.env # 编辑 config.env,至少修改: # POSTGRES_DSN 中的 password # MONGO_DSN(生产用 FwhToolboxDb) # MINIO_ACCESS_KEY / MINIO_SECRET_KEY # MYSQL_DSN 只读账号 # FWH_PASSWORD / FWH_TEST_PASSWORD 等密钥 ``` 关键项对照(详见模板注释): | 变量 | 示例/默认 | 说明 | | --- | --- | --- | | `APP_PORT` | `8301` | 后端监听端口(localhost) | | `ASYNQMON_PORT` | `8302` | 任务监控面板端口 | | `POSTGRES_DSN` | `host=localhost user=fwh_toolbox password=... dbname=fwh_toolbox_db port=5432 sslmode=disable` | 本地 PG | | `MONGO_DSN` | `mongodb://127.0.0.1:27017/FwhToolboxDb` | 本地 Mongo | | `REDIS_ADDR` | `localhost:6379` | 本地 Redis | | `MINIO_ENDPOINT` | `localhost:9198` | MinIO S3 API | | `MINIO_BUCKET_NAME` | `fwh-toolbox` | 业务 bucket | | `MYSQL_DSN` | 远程只读账号 | FWH 生产库 | > **MQTT 证书**:把 `cert/pro/` 与 `cert/test/` 下的 CA/证书/私钥放到 > `server/cert/` 对应目录(路径与 `config.env` 中 `FWH_MQTT_*` 保持相对一致)。 > 证书文件属敏感凭据,请勿提交到仓库。 --- ## 7. 构建与部署后端 ### 7.1 手动方式 ```bash cd service GOOS=linux GOARCH=amd64 go build -o fwh-toolbox-server ./ GOOS=linux GOARCH=amd64 go build -o fwh-mcp-server ./cmd/mcp/ sudo mkdir -p /var/www/fwh-toolbox/server sudo mv fwh-toolbox-server fwh-mcp-server /var/www/fwh-toolbox/server/ sudo cp config.env /var/www/fwh-toolbox/server/config.env # 拷贝证书目录 sudo cp -r cert /var/www/fwh-toolbox/server/ ``` ### 7.2 systemd 服务 创建 `/etc/systemd/system/fwh-toolbox-server.service`: ```ini [Unit] Description=fwh-toolbox-server service After=network.target postgresql.service mongod.service redis-server.service minio.service [Service] ExecStart=/var/www/fwh-toolbox/server/fwh-toolbox-server Restart=always User=jerry-remote WorkingDirectory=/var/www/fwh-toolbox/server CPUQuota=200% MemoryLimit=2G [Install] WantedBy=multi-user.target ``` ```bash sudo systemctl daemon-reload sudo systemctl enable --now fwh-toolbox-server sudo systemctl status fwh-toolbox-server --no-pager ``` > `User` 应与配置的 `KIRO_RUN_AS_USER` 一致,并保证该用户对 > `WorkingDirectory` 及 `cert/`、`function/` 等目录有读写权限。 ### 7.3 一键脚本 ```bash cd deploy/scripts chmod +x deploy.sh ./deploy.sh backend # 仅后端 ``` --- ## 8. 构建与部署前端 前端使用 Vite(rolldown-vite),生产环境变量见 `.env.production`: - `VITE_PUBLIC_PATH = /fwh-toolbox/`(与反代路径一致) - `VITE_API_URL = /fwh-toolbox/api` - `VITE_ROUTER_MODE = hash` ### 8.1 手动方式 ```bash # 仓库根目录 pnpm install --frozen-lockfile pnpm build # 产物在 ./dist sudo mkdir -p /var/www/fwh-toolbox/fwh-toolbox sudo rm -rf /var/www/fwh-toolbox/fwh-toolbox/* sudo cp -rf ./dist/* /var/www/fwh-toolbox/fwh-toolbox/ ``` > `package.json` 中的 `install` 脚本即等价于上面的拷贝操作。 ### 8.2 前端静态托管 线上由本地 Web 服务器(Apache,监听 8300)托管该静态目录,再由 Caddy 反代。 用 Apache 为例,站点根指向 `/var/www/fwh-toolbox/fwh-toolbox`,监听 8300。 也可直接用 Caddy 的 `file_server` 托管,省去 Apache。 ### 8.3 一键脚本 ```bash cd deploy/scripts ./deploy.sh frontend # 仅前端 # 或 ./deploy.sh all # 前端 + 后端 ``` --- ## 9. 反向代理(Caddy) 本项目使用**自编译的 Caddy**(内置 `dns.providers.spaceship` 插件,用于 DNS-01 签发 证书),二进制随仓库提供于 `deploy/bin/caddy`。**不要用 `apt install caddy`**(官方包 不含 spaceship 插件)。 推荐用脚本一键部署(部署二进制 + systemd 服务 + 生成站点配置): ```bash cd deploy/scripts chmod +x install_caddy.sh CADDY_DOMAIN='你的域名' \ LIBDNS_SPACESHIP_APIKEY='你的APIKey' \ LIBDNS_SPACESHIP_APISECRET='你的APISecret' \ ./install_caddy.sh ``` 脚本会: 1. 拷贝 `deploy/bin/caddy` -> `/usr/bin/caddy`,并校验含 spaceship 模块; 2. 生成 systemd 服务 `/lib/systemd/system/caddy.service`(`User=caddy`、 `run --environ`,把 DNS token 写入 `Environment=`,文件权限 600); 3. 生成站点文件 `/etc/caddy/sites/fwh-toolbox.caddy`(TLS 走 spaceship DNS-01), 并确保主 `/etc/caddy/Caddyfile` 含 `import sites/*.caddy`; 4. `validate` 后 `reload`/`restart`。 在站点 Caddyfile 中加入以下片段(`你的域名` 替换为实际域名)。前端静态走 8300, API 走 8301(与 `VITE_API_URL=/fwh-toolbox/api` 对应): > **配置路径参考**(与 `install_caddy.sh` 一致,线上同此结构): > - 主配置:`/etc/caddy/Caddyfile`(含 `import sites/*.caddy`); > - 站点片段:`/etc/caddy/sites/fwh-toolbox.caddy`。 ```caddyfile 你的域名 { tls { dns spaceship { api_key {env.LIBDNS_SPACESHIP_APIKEY} api_secret {env.LIBDNS_SPACESHIP_APISECRET} } propagation_timeout 10m propagation_delay 5m resolvers 8.8.8.8 } encode zstd gzip # fwh-toolbox 前端 + API redir /fwh-toolbox /fwh-toolbox/ 301 handle /fwh-toolbox/* { # API:/fwh-toolbox/api/* -> 后端 8301(去掉前缀) handle_path /fwh-toolbox/api/* { reverse_proxy localhost:8301 } # 其余:前端静态 8300 reverse_proxy localhost:8300 } # MinIO 控制台(可选) redir /fwh-minio /fwh-minio/ 301 handle_path /fwh-minio/* { reverse_proxy localhost:9199 } } ``` > DNS token 经 systemd `Environment=` 注入,配置里只用 `{env.XXX}` 引用,不写明文。 > 服务文件含明文 token,权限已设 600,**切勿提交到仓库**。 > 线上实际由 Apache 在 8300 托管静态、Caddy 统一入口反代;也可让 Caddy 直接 > `file_server` 托管 `/var/www/fwh-toolbox/fwh-toolbox`,二选一即可。 重载: ```bash sudo systemctl reload caddy # 或 /usr/bin/caddy reload --config /etc/caddy/Caddyfile --force ``` --- ## 10. Casdoor 认证服务安装与配置 前后端的登录鉴权由 [Casdoor](https://casdoor.org/) 提供(OAuth/OIDC + JWT)。 线上以 **Docker** 方式运行 `casbin/casdoor`,容器端口 `8000` 映射到宿主 `8010`, 后端 PostgreSQL 中有独立的 `casdoor` 数据库存放其数据,Caddy 将 `/casdoor/*` 反代到 `localhost:8010`。 ### 10.1 一键安装(推荐) ```bash cd deploy/scripts chmod +x install_casdoor.sh CASDOOR_PG_PASSWORD='强密码' ./install_casdoor.sh ``` 脚本会: 1. 在本地 PostgreSQL 创建角色 `casdoor` 与数据库 `casdoor`(幂等); 2. 在 `~/docker/casdoor/` 生成 `docker-compose.yml` 与 `conf/app.conf`; 3. 首次以 `--createDatabase=true` 建表并写入初始数据; 4. `docker compose up -d` 启动容器(默认端口 `8010`)。 > 也可在 `setup.sh` 向导中勾选「安装 Casdoor」步骤,本地/远程均支持 > (远程会自动确保 Docker 已安装)。 可用环境变量:`CASDOOR_DIR`、`CASDOOR_PORT`、`CASDOOR_PG_USER`、 `CASDOOR_PG_PASSWORD`、`CASDOOR_DB_NAME`、`CASDOOR_ORIGIN`。 ### 10.2 PostgreSQL 连接说明(容器 → 宿主机) Casdoor 在容器内,需通过 `host.docker.internal`(compose 里已配 `host-gateway`) 访问宿主机 PostgreSQL。确保宿主 PostgreSQL 允许该连接: ```bash # postgresql.conf listen_addresses = '*' # 或至少包含 docker 网关地址 # pg_hba.conf 增加一行(Docker 默认网段) host casdoor casdoor 172.16.0.0/12 scram-sha-256 sudo systemctl reload postgresql ``` `app.conf` 中的数据源形如: ```ini driverName = postgres dataSourceName = user=casdoor password=*** host=host.docker.internal port=5432 sslmode=disable dbname= dbName = casdoor ``` ### 10.3 手动安装(等价步骤) ```bash mkdir -p ~/docker/casdoor/conf && cd ~/docker/casdoor # docker-compose.yml cat > docker-compose.yml <<'EOF' services: casdoor: restart: always image: casbin/casdoor:latest entrypoint: /bin/sh -c './server' ports: - "8010:8000" environment: RUNNING_IN_DOCKER: "true" extra_hosts: - "host.docker.internal:host-gateway" volumes: - ./conf:/conf/ EOF # conf/app.conf 见 install_casdoor.sh 生成的模板 docker compose up -d ``` ### 10.4 在 Casdoor 中配置组织与应用 首次访问 `http://<服务器>:8010`(或经反代 `/casdoor`),默认管理员 **admin / 123** (登录后请立即改密)。然后: 1. **创建组织**:名称必须为 `organization_franklinwh_toolbox` (与前后端硬编码一致)。 2. **创建应用**:名称 `app-franklinwh-toolbox`,归属上面的组织。 - 记录 **Client ID** 与 **Client Secret**; - 在 **Redirect URLs** 添加前端回调地址: - 生产:`https://<域名>/fwh-toolbox/casdoor/callback` - 测试:`https://<域名>/fwh-toolbox-test/casdoor/callback` (前端 `redirectPath = ${VITE_PUBLIC_PATH}/casdoor/callback`) - 勾选授权模式(Authorization Code)与需要的登录方式。 3. **获取应用证书**:在应用的 Cert 中查看/下载 X.509 证书(PEM), 后端用它验证 JWT 签名。 ### 10.5 前后端如何消费 Casdoor - **前端**(`src/utils/casdoor/casdoor.ts`)硬编码: `serverUrl = /casdoor`、`clientId`、`appName = app-franklinwh-toolbox`、 `organizationName = organization_franklinwh_toolbox`、 `redirectPath = ${VITE_PUBLIC_PATH}/casdoor/callback`。 如更换 Casdoor 应用,需同步修改此文件里的 `ClientId` 并重新构建前端。 - **后端**(`service/utils/casdoor/casdoor.go`)硬编码: `endpoint`、`clientId`、`clientSecret`、`certificate`、`organizationName`、 `applicationName`。更换应用/证书后需修改这些常量并重新构建后端。 > ⚠️ 这些值当前写死在源码中而非 `config.env`。在新环境部署时, > 若沿用同一套 Casdoor 应用与证书则无需改动;若新建 Casdoor 应用, > 必须更新上述前后端源码常量并重新构建。 ### 10.6 反向代理 Caddyfile 中加入(`/casdoor/*` → 容器映射端口 8010): ```caddyfile 你的域名 { # ... 其他 handle ... redir /casdoor /casdoor/ 301 handle_path /casdoor/* { reverse_proxy localhost:8010 } } ``` `handle_path` 会去掉 `/casdoor` 前缀,与 Casdoor 容器根路径匹配。 ### 10.7 验证 ```bash docker compose -f ~/docker/casdoor/docker-compose.yml ps curl -sS http://127.0.0.1:8010/ | head # 返回 Casdoor 首页 sudo -u postgres psql -d casdoor -c "\dt" | head # 应有 casdoor 的数据表 # 经反代 curl -skS https://<域名>/casdoor/ | head ``` --- ## 11. 启动、验证与排错 ### 11.1 启动顺序 ```bash sudo systemctl status postgresql mongod redis-server minio --no-pager sudo systemctl restart fwh-toolbox-server sudo systemctl reload caddy ``` ### 11.2 验证 ```bash # 后端存活(本机) curl -sS http://127.0.0.1:8301/swagger/index.html | head # 任务面板 curl -sS http://127.0.0.1:8302/asynqmon/ | head # 前端(经反代) curl -skS https://你的域名/fwh-toolbox/ | head # PostgreSQL sudo -u postgres psql -d fwh_toolbox_db -c "\dt alarm_snapshot.*" # MinIO bucket mc ls fwhlocal/ ``` ### 11.3 日志 ```bash sudo journalctl -u fwh-toolbox-server -f # 项目自带脚本 service/cmd/showTodayLog.sh service/cmd/showTodayErrorLog.sh ``` ### 11.4 常见问题 - **后端启动 panic:database init failed** —— PostgreSQL 未就绪或 `POSTGRES_DSN` 错误。确认库/角色已由 `init_pgsql.sql` 创建、密码一致、`sslmode=disable`。 - **Mongo ping error** —— `mongod` 未运行或 `MONGO_DSN` 主机端口错误。 - **前端 404 / 资源路径错乱** —— `VITE_PUBLIC_PATH` 必须为 `/fwh-toolbox/`, 且反代路径一致。 - **API 请求 404** —— 检查 Caddy 的 `handle_path /fwh-toolbox/api/*` 是否正确 去前缀并指向 8301。 - **MinIO 上传失败** —— bucket 不存在或 AK/SK 不匹配,用 `mc` 检查。 --- ## 12. 附录:一键脚本清单 | 文件 | 作用 | | --- | --- | | `deploy/DEPLOYMENT.md` | 本部署文档 | | `deploy/CHECKLIST.md` | 部署清单(需填写项 + 步骤,可勾选) | | `deploy/start.sh` | **部署入口**(从这里开始,转发到交互式向导 setup.sh) | | `deploy/scripts/setup.sh` | **交互式一键部署**(本地/远程,分步选择与填写) | | `deploy/scripts/install_deps.sh` | 检测并(按需)安装 PostgreSQL/MongoDB/Redis/MinIO/mc/Docker(`DETECT_ONLY=1` 仅检测) | | `deploy/scripts/install_casdoor.sh` | 以 Docker 部署 Casdoor + 建其 PostgreSQL 库/角色 | | `deploy/sql/init_pgsql.sql` | PostgreSQL 从零建角色/库/schema/表(幂等) | | `deploy/scripts/init_databases.sh` | 初始化本地数据库(PG 建表 + Mongo/Redis 连通性检查;不含 MinIO) | | `deploy/scripts/provision_minio.sh` | 创建 MinIO 业务账号与最小权限策略(`fwh-toolbox` / `fwh-toolbox-ai`) | | `deploy/scripts/install_pgadmin.sh` | 给 `postgres` 设密码 + Docker 部署 Web 版 pgAdmin4 | | `deploy/scripts/install_caddy.sh` | 部署自编译 Caddy(spaceship DNS)+ systemd 服务 + 生成站点配置 | | `deploy/bin/caddy` | 自编译 Caddy 二进制(内置 `dns.providers.spaceship` 插件) | | `deploy/scripts/deploy.sh` | 构建并部署前端/后端(`all`/`frontend`/`backend`) | | `deploy/config.env.example` | 后端配置模板 | | `service/cmd/deploy_toolbox.sh` | 仅构建部署后端主程序(历史脚本) | | `service/cmd/deploy_mcp.sh` | 仅构建部署 MCP(历史脚本) | ### 全新服务器最短部署路径 最省事:直接跑交互式向导 `./deploy/scripts/setup.sh`(勾选“安装依赖”“安装 Casdoor” “初始化数据库”“部署后端/前端”即可)。以下为等价的分步命令: ```bash # 0) 克隆代码 git clone FranklinWH-ToolBox && cd FranklinWH-ToolBox # 1) 检测/安装依赖(数据库引擎 + Docker) cd deploy/scripts && chmod +x *.sh MINIO_ROOT_USER='admin' MINIO_ROOT_PASSWORD='强密码' \ ./install_deps.sh postgres mongo redis minio mc docker # 2) 安装 Casdoor(认证服务,Docker) CASDOOR_PG_PASSWORD='强密码' ./install_casdoor.sh # 3) 初始化数据库(建库/建表 + Mongo/Redis 检查;不含 MinIO) PG_FWH_PASSWORD='强密码' ./init_databases.sh # 3.1) 创建 MinIO 桶 + 业务账号 + 策略(fwh-toolbox / fwh-toolbox-ai) MINIO_ROOT_USER='admin' MINIO_ROOT_PASSWORD='强密码' \ MINIO_SECRET_KEY='业务强密码' MINIO_AI_SECRET_KEY='AI强密码' ./provision_minio.sh # 4) 配置后端(回到仓库根目录) cd ../.. cp deploy/config.env.example service/config.env && vim service/config.env # 填入真实密钥 mkdir -p service/cert/pro service/cert/test # 放入 MQTT 证书 # 5) 部署前后端 ./deploy/scripts/deploy.sh all # 6) 部署 Caddy(自编译 + spaceship DNS) CADDY_DOMAIN='你的域名' LIBDNS_SPACESHIP_APIKEY='xxx' LIBDNS_SPACESHIP_APISECRET='xxx' \ ./deploy/scripts/install_caddy.sh # 7) 在 Casdoor 建组织/应用(第 10 章),完成 ```