本文档描述如何在一台全新的 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。
下面列出必须由你确认或填写的项。脚本与 config.env.example 中对应位置均已用
# TODO: 注释标出,可搜索 TODO 快速定位。
📋 完整的可勾选清单(含填写项与部署步骤)见 CHECKLIST.md。
必填(不改则无法正常运行 / 有安全风险)
fwh_toolbox 角色密码:init_databases.sh 的 PG_FWH_PASSWORD
与 config.env 的 POSTGRES_DSN 中 password= 必须一致。MINIO_ROOT_USER/MINIO_ROOT_PASSWORD(勿用默认 minioadmin)。config.env 的 MINIO_ACCESS_KEY/MINIO_SECRET_KEY。config.env 的 FWH_USER/FWH_PASSWORD。server/cert/pro/,并核对 config.env 中路径。CASDOOR_PG_PASSWORD(勿用默认 casdoor)。organization_franklinwh_toolbox /
app-franklinwh-toolbox,若新建应用需把 clientId/secret/证书同步到源码
(service/utils/casdoor/casdoor.go、src/utils/casdoor/casdoor.ts)后重新构建。你的域名、Casdoor origin/回调 URL。LIBDNS_SPACESHIP_APIKEY/APISECRET(spaceship DNS-01 签证书用,
写入 systemd 服务,勿提交仓库)。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_TEST_*)。PLANE_*)。交互式脚本
deploy/scripts/setup.sh会逐项提示你填写以上内容,推荐优先使用。
如果只想尽快完成部署,直接运行交互式脚本 deploy/scripts/setup.sh。它会分步引导
你选择/填写内容,并支持本地与远程(SSH)两种目标:
cd deploy/scripts
chmod +x setup.sh
./setup.sh
向导流程:
设计要点:
想了解每一步的底层动作、或需要单独执行某一环节,请继续阅读后续章节;
setup.sh内部即是对第 5~8 章操作的编排。
┌─────────────────────────────────────────┐
浏览器 ── 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 为必需。
| 组件 | 端口 | 绑定 | 备注 |
|---|---|---|---|
| 后端 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/)
以下命令在全新 Ubuntu 22.04 上以具备 sudo 权限的用户执行。
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git build-essential ca-certificates gnupg lsb-release
参照线上使用官方二进制安装(不使用 apt 版本,避免过旧):
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
# 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
后端 AI 对话 / MCP 相关能力可能通过 uvx 拉起基于 Python 的 MCP server,需要 uv。
install_deps.sh 会自动检测并安装(缺失时),也可手动安装:
# 官方脚本,安装到 /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
自动检测/安装:可直接用
deploy/scripts/install_deps.sh一次性完成本章 各数据库引擎的检测与(缺失时)安装(幂等,可重复运行):> 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 14bash 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.xbash 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
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
sudo tee /etc/default/minio > /dev/null <<'EOF' MINIO_VOLUMES="/var/lib/minio/data"
MINIO_OPTS="--address :9198 --console-address :9199" MINIO_ROOT_USER="CHANGE_ME_ADMIN" MINIO_ROOT_PASSWORD="CHANGE_ME_STRONG_PASSWORD" EOF
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
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
sudo -u postgres pg_dump -Fc -d fwh_toolbox_db -f /tmp/fwh_toolbox_db.dump
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
cp deploy/config.env.example service/config.env
关键项对照(详见模板注释):
| 变量 | 示例/默认 | 说明 |
| --- | --- | --- |
| `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 # 仅前端
---
## 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
---
## 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
listen_addresses = '*' # 或至少包含 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
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
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
sudo -u postgres psql -d fwh_toolbox_db -c "\dt alarm_snapshot.*"
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/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
git clone FranklinWH-ToolBox && cd FranklinWH-ToolBox
cd deploy/scripts && chmod +x *.sh MINIO_ROOT_USER='admin' MINIO_ROOT_PASSWORD='强密码' \ ./install_deps.sh postgres mongo redis minio mc docker
CASDOOR_PG_PASSWORD='强密码' ./install_casdoor.sh
PG_FWH_PASSWORD='强密码' ./init_databases.sh
MINIO_ROOT_USER='admin' MINIO_ROOT_PASSWORD='强密码' \ MINIO_SECRET_KEY='业务强密码' MINIO_AI_SECRET_KEY='AI强密码' ./provision_minio.sh
cd ../.. cp deploy/config.env.example service/config.env && vim service/config.env # 填入真实密钥 mkdir -p service/cert/pro service/cert/test # 放入 MQTT 证书
./deploy/scripts/deploy.sh all
CADDY_DOMAIN='你的域名' LIBDNS_SPACESHIP_APIKEY='xxx' LIBDNS_SPACESHIP_APISECRET='xxx' \ ./deploy/scripts/install_caddy.sh
```