|
|
@@ -31,6 +31,7 @@ PROJECT_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)" # 仓库根目录
|
|
|
SERVICE_DIR="${PROJECT_ROOT}/service"
|
|
|
SQL_FILE="${DEPLOY_DIR}/sql/init_pgsql.sql"
|
|
|
CONFIG_EXAMPLE="${DEPLOY_DIR}/config.env.example"
|
|
|
+MCP_CONFIG_EXAMPLE="${DEPLOY_DIR}/config.mcp.env.example"
|
|
|
|
|
|
APP_NAME="fwh-toolbox-server"
|
|
|
MCP_NAME="fwh-mcp-server"
|
|
|
@@ -66,6 +67,23 @@ ask_secret() {
|
|
|
printf -v "${__var}" '%s' "${__ans}"
|
|
|
}
|
|
|
|
|
|
+# 强制输入密码(不回显、无默认,必须非空且两次一致):ask_secret_required VAR "提示"
|
|
|
+ask_secret_required() {
|
|
|
+ local __var="$1" __prompt="$2" __a __b
|
|
|
+ while :; do
|
|
|
+ read -r -s -p "$(echo -e "${c_bold}${__prompt}${c_reset}: ")" __a; echo
|
|
|
+ if [[ -z "${__a}" ]]; then
|
|
|
+ warn "不能为空,请重新输入。"; continue
|
|
|
+ fi
|
|
|
+ read -r -s -p "$(echo -e "${c_bold}${__prompt}(再输一次确认)${c_reset}: ")" __b; echo
|
|
|
+ if [[ "${__a}" != "${__b}" ]]; then
|
|
|
+ warn "两次输入不一致,请重新输入。"; continue
|
|
|
+ fi
|
|
|
+ break
|
|
|
+ done
|
|
|
+ printf -v "${__var}" '%s' "${__a}"
|
|
|
+}
|
|
|
+
|
|
|
# 是/否确认:ask_yn "提示" "y|n(默认)" -> 返回 0=yes 1=no
|
|
|
ask_yn() {
|
|
|
local __prompt="$1" __default="${2:-y}" __ans
|
|
|
@@ -83,7 +101,7 @@ require_cmd() {
|
|
|
# 全局变量(向导填写)
|
|
|
# ---------------------------------------------------------------------------
|
|
|
MODE="" # local | remote
|
|
|
-DO_DEPS="y"; DO_CASDOOR="n"; DO_INITDB="y"; DO_BACKEND="y"; DO_FRONTEND="y"; DO_GENCONF="y"; DO_CADDY="n"; DO_KIRO="n"
|
|
|
+DO_DEPS="y"; DO_CASDOOR="n"; DO_INITDB="y"; DO_BACKEND="y"; DO_FRONTEND="y"; DO_GENCONF="y"; DO_CADDY="n"; DO_KIRO="n"; DO_PGADMIN="n"; DO_MINIOACCT="y"
|
|
|
|
|
|
# 远程连接
|
|
|
R_HOST=""; R_PORT="22"; R_USER=""; R_SSH_KEY=""
|
|
|
@@ -101,8 +119,14 @@ PG_HOST="localhost"; PG_PORT="5432"; PG_DB="fwh_toolbox_db"; PG_USER="fwh_toolbo
|
|
|
MONGO_DSN="mongodb://127.0.0.1:27017/FwhToolboxDb"
|
|
|
REDIS_ADDR="localhost:6379"
|
|
|
MYSQL_DSN="" # TODO: [必填/可选] 远端只读 MySQL DSN,用到站点查询才需填
|
|
|
-MINIO_ENDPOINT="localhost:9198"; MINIO_ACCESS_KEY=""; MINIO_SECRET_KEY=""; MINIO_BUCKET="fwh-toolbox" # TODO: [必填] MinIO AK/SK
|
|
|
-MINIO_ROOT_USER="minioadmin"; MINIO_ROOT_PASSWORD="minioadmin" # TODO: [必填] MinIO 管理员改强口令
|
|
|
+MINIO_ENDPOINT="localhost:9198"; MINIO_ACCESS_KEY="fwh-toolbox"; MINIO_SECRET_KEY="fwh-toolbox"; MINIO_BUCKET="fwh-toolbox" # TODO: [确认] MinIO 业务 AK/SK(默认 fwh-toolbox)
|
|
|
+MINIO_AI_ACCESS_KEY="fwh-toolbox-ai"; MINIO_AI_SECRET_KEY="fwh-toolbox-ai"; MINIO_AI_BUCKET="fwh-toolbox-ai-file" # MCP 用 AI 账号(provision_minio.sh 创建)
|
|
|
+MINIO_ROOT_USER="jerry"; MINIO_ROOT_PASSWORD="" # TODO: [必填] MinIO 管理员密码向导内强制输入
|
|
|
+
|
|
|
+# pgAdmin4(数据库 Web 管理,可选)
|
|
|
+PGADMIN_PORT="5480"; PGADMIN_BIND="127.0.0.1"; PGADMIN_EMAIL="liang_jlyx@163.com"
|
|
|
+PGADMIN_PASSWORD="" # TODO: [必填] 向导内强制输入
|
|
|
+POSTGRES_ADMIN_PASSWORD="" # TODO: [必填] 向导内强制输入
|
|
|
|
|
|
# Casdoor
|
|
|
CASDOOR_DIR=""; CASDOOR_PORT="8010"
|
|
|
@@ -111,9 +135,7 @@ CASDOOR_ORIGIN="" # TODO: [必填] Casdo
|
|
|
|
|
|
# Caddy 反向代理
|
|
|
CADDY_DOMAIN="" # TODO: [必填] 对外域名,如 lmt.zenpower.cc
|
|
|
-CADDY_TLS_MODE="internal" # internal | acme | manual
|
|
|
-CADDY_ACME_EMAIL="" # acme 模式邮箱(可空,走默认 ACME)
|
|
|
-CADDY_TLS_CERT=""; CADDY_TLS_KEY="" # manual 模式证书/私钥路径
|
|
|
+LIBDNS_SPACESHIP_APIKEY=""; LIBDNS_SPACESHIP_APISECRET="" # TODO: [必填] spaceship DNS API 凭据(向导内输入,写入 systemd 服务)
|
|
|
CADDY_FRONTEND_PORT="8300"; CADDY_BACKEND_PORT="8301"
|
|
|
CADDY_INCLUDE_CASDOOR="n"; CADDY_INCLUDE_MINIO="n"
|
|
|
CADDY_SERVE_STATIC="n" # 由 Caddy 直接 file_server 托管前端
|
|
|
@@ -125,6 +147,7 @@ KIRO_DO_LOGIN="n" # 安装后是否立即
|
|
|
|
|
|
# 生成的配置文件(本地临时路径)
|
|
|
GEN_CONFIG=""
|
|
|
+GEN_MCP_CONFIG=""
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
# 步骤 0:选择模式与步骤
|
|
|
@@ -157,6 +180,8 @@ wizard_intro() {
|
|
|
fi
|
|
|
ask_yn "⑦ 安装并配置 Caddy 反向代理(生成站点 Caddyfile 并 reload)?" "n" && DO_CADDY="y" || DO_CADDY="n"
|
|
|
ask_yn "⑧ 安装 Kiro CLI(后端 AI 对话依赖,需以运行用户登录 Builder ID)?" "n" && DO_KIRO="y" || DO_KIRO="n"
|
|
|
+ ask_yn "⑨ 部署 pgAdmin4(Docker,数据库 Web 管理,并给 postgres 设密码)?" "n" && DO_PGADMIN="y" || DO_PGADMIN="n"
|
|
|
+ ask_yn "⑩ 创建 MinIO 业务账号与策略(fwh-toolbox / fwh-toolbox-ai)?" "y" && DO_MINIOACCT="y" || DO_MINIOACCT="n"
|
|
|
}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
@@ -247,10 +272,10 @@ wizard_params() {
|
|
|
ask MINIO_BUCKET "MinIO Bucket 名" "fwh-toolbox"
|
|
|
fi
|
|
|
|
|
|
- if [[ "${DO_INITDB}" == "y" || "${DO_DEPS}" == "y" ]]; then
|
|
|
- title "MinIO 管理员账户(安装/建桶用)"
|
|
|
- ask MINIO_ROOT_USER "MinIO 管理员用户" "minioadmin"
|
|
|
- ask_secret MINIO_ROOT_PASSWORD "MinIO 管理员密码" "minioadmin"
|
|
|
+ if [[ "${DO_INITDB}" == "y" || "${DO_DEPS}" == "y" || "${DO_MINIOACCT}" == "y" ]]; then
|
|
|
+ title "MinIO 管理员账户(安装/建桶/建账号用)"
|
|
|
+ ask MINIO_ROOT_USER "MinIO 管理员用户" "jerry"
|
|
|
+ ask_secret_required MINIO_ROOT_PASSWORD "MinIO 管理员密码(必填)"
|
|
|
fi
|
|
|
|
|
|
if [[ "${DO_CASDOOR}" == "y" ]]; then
|
|
|
@@ -264,20 +289,33 @@ wizard_params() {
|
|
|
ask CASDOOR_ORIGIN "Casdoor 对外访问地址(origin)" "http://localhost:${CASDOOR_PORT}"
|
|
|
fi
|
|
|
|
|
|
+ if [[ "${DO_PGADMIN}" == "y" ]]; then
|
|
|
+ title "pgAdmin4(数据库 Web 管理)"
|
|
|
+ ask PGADMIN_PORT "pgAdmin4 对外端口" "5480"
|
|
|
+ ask PGADMIN_BIND "pgAdmin4 绑定地址(默认仅本机,防公网暴露)" "127.0.0.1"
|
|
|
+ ask PGADMIN_EMAIL "pgAdmin4 登录邮箱" "liang_jlyx@163.com"
|
|
|
+ ask_secret_required PGADMIN_PASSWORD "pgAdmin4 登录密码(必填)"
|
|
|
+ ask_secret_required POSTGRES_ADMIN_PASSWORD "postgres 超级用户新密码(供 pgAdmin 连接,必填)"
|
|
|
+ fi
|
|
|
+
|
|
|
+ if [[ "${DO_MINIOACCT}" == "y" ]]; then
|
|
|
+ title "MinIO 业务账号(后端 fwh-toolbox / MCP fwh-toolbox-ai)"
|
|
|
+ # 业务账号:默认 fwh-toolbox;若已在生成 config 时填过则复用,此处不重复询问
|
|
|
+ [[ -n "${MINIO_ACCESS_KEY}" ]] || ask MINIO_ACCESS_KEY "后端业务 Access Key" "fwh-toolbox"
|
|
|
+ [[ -n "${MINIO_SECRET_KEY}" ]] || ask_secret MINIO_SECRET_KEY "后端业务 Secret Key" "fwh-toolbox"
|
|
|
+ # AI 账号(供 MCP 使用)
|
|
|
+ ask MINIO_AI_ACCESS_KEY "AI Access Key(MCP 用)" "fwh-toolbox-ai"
|
|
|
+ ask_secret MINIO_AI_SECRET_KEY "AI Secret Key(MCP 用,默认与账号一致)" "fwh-toolbox-ai"
|
|
|
+ ask MINIO_AI_BUCKET "AI 文件 bucket 名" "fwh-toolbox-ai-file"
|
|
|
+ fi
|
|
|
+
|
|
|
if [[ "${DO_CADDY}" == "y" ]]; then
|
|
|
title "Caddy 反向代理"
|
|
|
ask CADDY_DOMAIN "对外域名 (如 lmt.zenpower.cc)"
|
|
|
[[ -n "${CADDY_DOMAIN}" ]] || { err "Caddy 域名不能为空"; exit 1; }
|
|
|
- echo "TLS 模式:1) internal(自签,测试) 2) acme(自动签发) 3) manual(指定证书)"
|
|
|
- local _tls_sel; ask _tls_sel "输入序号" "1"
|
|
|
- case "${_tls_sel}" in
|
|
|
- 1) CADDY_TLS_MODE="internal" ;;
|
|
|
- 2) CADDY_TLS_MODE="acme"; ask CADDY_ACME_EMAIL "ACME 邮箱(可留空走默认)" "" ;;
|
|
|
- 3) CADDY_TLS_MODE="manual"
|
|
|
- ask CADDY_TLS_CERT "证书文件路径 (.pem/.crt)"
|
|
|
- ask CADDY_TLS_KEY "私钥文件路径 (.key)" ;;
|
|
|
- *) err "无效选择"; exit 1 ;;
|
|
|
- esac
|
|
|
+ echo "TLS 走 spaceship DNS-01(自编译 caddy 内置该插件),请输入 spaceship API 凭据:"
|
|
|
+ ask_secret_required LIBDNS_SPACESHIP_APIKEY "spaceship API Key(必填)"
|
|
|
+ ask_secret_required LIBDNS_SPACESHIP_APISECRET "spaceship API Secret(必填)"
|
|
|
ask CADDY_FRONTEND_PORT "前端静态端口" "8300"
|
|
|
ask CADDY_BACKEND_PORT "后端 API 端口" "${APP_PORT}"
|
|
|
ask_yn "由 Caddy 直接 file_server 托管前端静态(否则反代到前端端口)?" "n" \
|
|
|
@@ -379,6 +417,70 @@ PY
|
|
|
sed -i -E "s#^KIRO_RUN_AS_USER=.*#KIRO_RUN_AS_USER=${RUN_USER}#" "${GEN_CONFIG}"
|
|
|
fi
|
|
|
ok "已生成配置:${GEN_CONFIG}"
|
|
|
+
|
|
|
+ # -----------------------------------------------------------------------
|
|
|
+ # 单独生成 config.mcp.env(基于 config.mcp.env.example)
|
|
|
+ # 与后端共享库/缓存/MinIO endpoint/MySQL 等,但 MinIO 使用 AI 专用账号
|
|
|
+ # fwh-toolbox-ai(对 fwh-toolbox-ai* 桶可读写、其余桶只读;MCP 工具仅只读)。
|
|
|
+ # -----------------------------------------------------------------------
|
|
|
+ if [[ -f "${MCP_CONFIG_EXAMPLE}" ]]; then
|
|
|
+ GEN_MCP_CONFIG="$(mktemp /tmp/fwh_config.mcp.env.XXXXXX)"
|
|
|
+ cp "${MCP_CONFIG_EXAMPLE}" "${GEN_MCP_CONFIG}"
|
|
|
+
|
|
|
+ # MCP 侧 MinIO 使用 AI 账号;默认账号=密码=fwh-toolbox-ai(可用环境变量覆盖)
|
|
|
+ local mcp_ak="${MINIO_AI_ACCESS_KEY:-fwh-toolbox-ai}"
|
|
|
+ local mcp_sk="${MINIO_AI_SECRET_KEY:-fwh-toolbox-ai}"
|
|
|
+
|
|
|
+ if command -v python3 >/dev/null 2>&1; then
|
|
|
+ APP_ENV="${APP_ENV}" PG_DSN="${pg_dsn}" MONGO_DSN="${MONGO_DSN}" \
|
|
|
+ REDIS_ADDR="${REDIS_ADDR}" MYSQL_DSN="${MYSQL_DSN}" \
|
|
|
+ MINIO_ENDPOINT="${MINIO_ENDPOINT}" MINIO_ACCESS_KEY="${mcp_ak}" \
|
|
|
+ MINIO_SECRET_KEY="${mcp_sk}" MINIO_BUCKET="${MINIO_BUCKET}" \
|
|
|
+ python3 - "${GEN_MCP_CONFIG}" <<'PY'
|
|
|
+import os, re, sys
|
|
|
+path = sys.argv[1]
|
|
|
+repl = {
|
|
|
+ "APP_ENV": os.environ["APP_ENV"],
|
|
|
+ "POSTGRES_DSN": os.environ["PG_DSN"],
|
|
|
+ "MONGO_DSN": os.environ["MONGO_DSN"],
|
|
|
+ "REDIS_ADDR": os.environ["REDIS_ADDR"],
|
|
|
+ "MINIO_ENDPOINT": os.environ["MINIO_ENDPOINT"],
|
|
|
+ "MINIO_ACCESS_KEY": os.environ["MINIO_ACCESS_KEY"],
|
|
|
+ "MINIO_SECRET_KEY": os.environ["MINIO_SECRET_KEY"],
|
|
|
+ "MINIO_BUCKET_NAME": os.environ["MINIO_BUCKET"],
|
|
|
+}
|
|
|
+mysql = os.environ.get("MYSQL_DSN", "")
|
|
|
+if mysql:
|
|
|
+ repl["MYSQL_DSN"] = mysql
|
|
|
+
|
|
|
+lines = open(path, encoding="utf-8").read().splitlines()
|
|
|
+out = []
|
|
|
+for line in lines:
|
|
|
+ m = re.match(r'^(\s*)([A-Z0-9_]+)\s*=', line)
|
|
|
+ if m and m.group(2) in repl:
|
|
|
+ out.append(f'{m.group(2)}="{repl[m.group(2)]}"')
|
|
|
+ else:
|
|
|
+ out.append(line)
|
|
|
+open(path, "w", encoding="utf-8").write("\n".join(out) + "\n")
|
|
|
+print("config.mcp.env 已生成")
|
|
|
+PY
|
|
|
+ else
|
|
|
+ warn "未找到 python3,改用 sed 简易替换(含特殊字符时请手工核对)"
|
|
|
+ _sed_mcp() { sed -i -E "s#^(${1})=.*#${1}=\"${2//#/\\#}\"#" "${GEN_MCP_CONFIG}"; }
|
|
|
+ _sed_mcp APP_ENV "${APP_ENV}"
|
|
|
+ _sed_mcp POSTGRES_DSN "${pg_dsn}"
|
|
|
+ _sed_mcp MONGO_DSN "${MONGO_DSN}"
|
|
|
+ _sed_mcp REDIS_ADDR "${REDIS_ADDR}"
|
|
|
+ [[ -n "${MYSQL_DSN}" ]] && _sed_mcp MYSQL_DSN "${MYSQL_DSN}"
|
|
|
+ _sed_mcp MINIO_ENDPOINT "${MINIO_ENDPOINT}"
|
|
|
+ _sed_mcp MINIO_ACCESS_KEY "${mcp_ak}"
|
|
|
+ _sed_mcp MINIO_SECRET_KEY "${mcp_sk}"
|
|
|
+ _sed_mcp MINIO_BUCKET_NAME "${MINIO_BUCKET}"
|
|
|
+ fi
|
|
|
+ ok "已生成配置:${GEN_MCP_CONFIG}"
|
|
|
+ else
|
|
|
+ warn "未找到 ${MCP_CONFIG_EXAMPLE},跳过 config.mcp.env 生成"
|
|
|
+ fi
|
|
|
}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
@@ -409,11 +511,17 @@ REMOTE_STAGE="/tmp/fwh-deploy-stage"
|
|
|
prepare_remote_stage() {
|
|
|
[[ "${MODE}" == "remote" ]] || return 0
|
|
|
title "上传部署产物到远程"
|
|
|
- ssh_run "rm -rf ${REMOTE_STAGE} && mkdir -p ${REMOTE_STAGE}/sql ${REMOTE_STAGE}/cert ${REMOTE_STAGE}/scripts"
|
|
|
+ ssh_run "rm -rf ${REMOTE_STAGE} && mkdir -p ${REMOTE_STAGE}/sql ${REMOTE_STAGE}/cert ${REMOTE_STAGE}/scripts ${REMOTE_STAGE}/bin"
|
|
|
# 辅助脚本(依赖安装/ Casdoor)
|
|
|
scp_to "${SCRIPT_DIR}/install_deps.sh" "${REMOTE_STAGE}/scripts/"
|
|
|
scp_to "${SCRIPT_DIR}/install_casdoor.sh" "${REMOTE_STAGE}/scripts/"
|
|
|
scp_to "${SCRIPT_DIR}/install_caddy.sh" "${REMOTE_STAGE}/scripts/"
|
|
|
+ # 自编译 caddy 二进制(仅在需要装 Caddy 时上传,约 45MB)
|
|
|
+ if [[ "${DO_CADDY}" == "y" && -f "${SCRIPT_DIR}/../bin/caddy" ]]; then
|
|
|
+ scp_to "${SCRIPT_DIR}/../bin/caddy" "${REMOTE_STAGE}/bin/"
|
|
|
+ fi
|
|
|
+ scp_to "${SCRIPT_DIR}/install_pgadmin.sh" "${REMOTE_STAGE}/scripts/"
|
|
|
+ scp_to "${SCRIPT_DIR}/provision_minio.sh" "${REMOTE_STAGE}/scripts/"
|
|
|
scp_to "${SCRIPT_DIR}/install_kiro_cli.sh" "${REMOTE_STAGE}/scripts/"
|
|
|
ssh_run "chmod +x ${REMOTE_STAGE}/scripts/*.sh"
|
|
|
# SQL 与二进制、前端、配置、证书
|
|
|
@@ -430,7 +538,12 @@ prepare_remote_stage() {
|
|
|
rm -f /tmp/fwh-dist.tgz
|
|
|
fi
|
|
|
[[ -n "${GEN_CONFIG}" ]] && scp_to "${GEN_CONFIG}" "${REMOTE_STAGE}/config.env"
|
|
|
- [[ -n "${GEN_CONFIG}" ]] && scp_to "${GEN_CONFIG}" "${REMOTE_STAGE}/config.mcp.env"
|
|
|
+ if [[ -n "${GEN_MCP_CONFIG}" ]]; then
|
|
|
+ scp_to "${GEN_MCP_CONFIG}" "${REMOTE_STAGE}/config.mcp.env"
|
|
|
+ elif [[ -n "${GEN_CONFIG}" ]]; then
|
|
|
+ # 回退:未单独生成 MCP 配置时沿用后端配置
|
|
|
+ scp_to "${GEN_CONFIG}" "${REMOTE_STAGE}/config.mcp.env"
|
|
|
+ fi
|
|
|
ok "产物已上传到远程 ${REMOTE_STAGE}"
|
|
|
}
|
|
|
|
|
|
@@ -450,8 +563,8 @@ step_deps() {
|
|
|
# 需要的组件:若要装 Casdoor 则一并确保 docker
|
|
|
# uv 作为 MCP/AI 对话运行时依赖(uvx 拉起 MCP server),默认一并检测安装
|
|
|
local comps="postgres mongo redis minio mc uv"
|
|
|
- [[ "${DO_CASDOOR}" == "y" ]] && comps="${comps} docker"
|
|
|
- run "MINIO_API_PORT='${api_port}' MINIO_ROOT_USER='${MINIO_ROOT_USER}' MINIO_ROOT_PASSWORD='${MINIO_ROOT_PASSWORD}' bash '${base}/install_deps.sh' ${comps}"
|
|
|
+ [[ "${DO_CASDOOR}" == "y" || "${DO_PGADMIN}" == "y" ]] && comps="${comps} docker"
|
|
|
+ run "MINIO_API_PORT='${api_port}' MINIO_ROOT_USER='${MINIO_ROOT_USER}' MINIO_ROOT_PASSWORD='$(printf '%s' "${MINIO_ROOT_PASSWORD}")' bash '${base}/install_deps.sh' ${comps}"
|
|
|
ok "依赖检测/安装完成"
|
|
|
}
|
|
|
|
|
|
@@ -469,6 +582,39 @@ step_casdoor() {
|
|
|
ok "Casdoor 安装步骤结束(后续配置见 DEPLOYMENT.md)"
|
|
|
}
|
|
|
|
|
|
+# ---------------------------------------------------------------------------
|
|
|
+# 部署 pgAdmin4(Docker)+ 给 postgres 设密码
|
|
|
+# ---------------------------------------------------------------------------
|
|
|
+step_pgadmin() {
|
|
|
+ [[ "${DO_PGADMIN}" == "y" ]] || return 0
|
|
|
+ title "部署 pgAdmin4(Web)"
|
|
|
+ local base; base="$(_scripts_base)"
|
|
|
+ run "POSTGRES_PASSWORD='$(printf '%s' "${POSTGRES_ADMIN_PASSWORD}")' \
|
|
|
+ PGADMIN_EMAIL='${PGADMIN_EMAIL}' \
|
|
|
+ PGADMIN_PASSWORD='$(printf '%s' "${PGADMIN_PASSWORD}")' \
|
|
|
+ PGADMIN_PORT='${PGADMIN_PORT}' PGADMIN_BIND='${PGADMIN_BIND}' \
|
|
|
+ PG_PORT='${PG_PORT}' \
|
|
|
+ bash '${base}/install_pgadmin.sh'"
|
|
|
+ ok "pgAdmin4 部署步骤结束(访问 http://${PGADMIN_BIND}:${PGADMIN_PORT})"
|
|
|
+}
|
|
|
+
|
|
|
+# ---------------------------------------------------------------------------
|
|
|
+# 创建 MinIO 业务账号与策略(fwh-toolbox / fwh-toolbox-ai)
|
|
|
+# ---------------------------------------------------------------------------
|
|
|
+step_minioacct() {
|
|
|
+ [[ "${DO_MINIOACCT}" == "y" ]] || return 0
|
|
|
+ title "创建 MinIO 业务账号与策略"
|
|
|
+ local base; base="$(_scripts_base)"
|
|
|
+ local minio_ep="http://${MINIO_ENDPOINT}"
|
|
|
+ run "MINIO_ENDPOINT='${minio_ep}' \
|
|
|
+ MINIO_ROOT_USER='${MINIO_ROOT_USER}' MINIO_ROOT_PASSWORD='$(printf '%s' "${MINIO_ROOT_PASSWORD}")' \
|
|
|
+ MINIO_ACCESS_KEY='${MINIO_ACCESS_KEY:-fwh-toolbox}' MINIO_SECRET_KEY='$(printf '%s' "${MINIO_SECRET_KEY:-fwh-toolbox}")' \
|
|
|
+ MINIO_AI_ACCESS_KEY='${MINIO_AI_ACCESS_KEY}' MINIO_AI_SECRET_KEY='$(printf '%s' "${MINIO_AI_SECRET_KEY}")' \
|
|
|
+ MINIO_BUCKET='${MINIO_BUCKET}' MINIO_AI_BUCKET='${MINIO_AI_BUCKET}' \
|
|
|
+ bash '${base}/provision_minio.sh'"
|
|
|
+ ok "MinIO 业务账号步骤结束(后端 ${MINIO_ACCESS_KEY:-fwh-toolbox} / MCP ${MINIO_AI_ACCESS_KEY})"
|
|
|
+}
|
|
|
+
|
|
|
# ---------------------------------------------------------------------------
|
|
|
# 安装/配置 Caddy 反向代理
|
|
|
# ---------------------------------------------------------------------------
|
|
|
@@ -476,9 +622,9 @@ step_caddy() {
|
|
|
[[ "${DO_CADDY}" == "y" ]] || return 0
|
|
|
title "安装/配置 Caddy 反向代理"
|
|
|
local base; base="$(_scripts_base)"
|
|
|
- run "CADDY_DOMAIN='${CADDY_DOMAIN}' CADDY_TLS_MODE='${CADDY_TLS_MODE}' \
|
|
|
- CADDY_ACME_EMAIL='${CADDY_ACME_EMAIL}' \
|
|
|
- CADDY_TLS_CERT='${CADDY_TLS_CERT}' CADDY_TLS_KEY='${CADDY_TLS_KEY}' \
|
|
|
+ run "CADDY_DOMAIN='${CADDY_DOMAIN}' \
|
|
|
+ LIBDNS_SPACESHIP_APIKEY='$(printf '%s' "${LIBDNS_SPACESHIP_APIKEY}")' \
|
|
|
+ LIBDNS_SPACESHIP_APISECRET='$(printf '%s' "${LIBDNS_SPACESHIP_APISECRET}")' \
|
|
|
CADDY_FRONTEND_PORT='${CADDY_FRONTEND_PORT}' CADDY_BACKEND_PORT='${CADDY_BACKEND_PORT}' \
|
|
|
CADDY_INCLUDE_CASDOOR='${CADDY_INCLUDE_CASDOOR}' CADDY_CASDOOR_PORT='${CASDOOR_PORT}' \
|
|
|
CADDY_INCLUDE_MINIO='${CADDY_INCLUDE_MINIO}' CADDY_MINIO_CONSOLE_PORT='9199' \
|
|
|
@@ -508,8 +654,7 @@ step_kiro() {
|
|
|
step_initdb() {
|
|
|
[[ "${DO_INITDB}" == "y" ]] || return 0
|
|
|
title "初始化数据库"
|
|
|
- local sql_path minio_ep
|
|
|
- minio_ep="http://${MINIO_ENDPOINT}"
|
|
|
+ local sql_path
|
|
|
if [[ "${MODE}" == "remote" ]]; then
|
|
|
sql_path="${REMOTE_STAGE}/sql/init_pgsql.sql"
|
|
|
else
|
|
|
@@ -525,13 +670,7 @@ step_initdb() {
|
|
|
run "command -v mongosh >/dev/null 2>&1 && mongosh --quiet '${MONGO_DSN%%/*}//${MONGO_DSN#*//}' --eval 'db.runCommand({ping:1}).ok' >/dev/null 2>&1 && echo mongo-ok || true"
|
|
|
run "command -v redis-cli >/dev/null 2>&1 && [ \"\$(redis-cli -h ${REDIS_ADDR%%:*} -p ${REDIS_ADDR##*:} ping 2>/dev/null)\" = PONG ] && echo redis-ok || true"
|
|
|
|
|
|
- # 3) MinIO bucket
|
|
|
- info "MinIO 建桶(若已存在则跳过)..."
|
|
|
- run "if command -v mc >/dev/null 2>&1; then \
|
|
|
- mc alias set fwhlocal '${minio_ep}' '${MINIO_ROOT_USER}' '${MINIO_ROOT_PASSWORD}' >/dev/null 2>&1 || true; \
|
|
|
- mc ls fwhlocal/'${MINIO_BUCKET}' >/dev/null 2>&1 || mc mb fwhlocal/'${MINIO_BUCKET}'; \
|
|
|
- echo minio-ok; \
|
|
|
- else echo 'no-mc(请手动在 MinIO 控制台建桶)'; fi"
|
|
|
+ # 注:MinIO 建桶 + 业务账号 + 策略统一由 step_minioacct(provision_minio.sh)负责,此处不再建桶。
|
|
|
ok "数据库初始化步骤结束"
|
|
|
}
|
|
|
|
|
|
@@ -559,7 +698,11 @@ step_backend() {
|
|
|
sudo chmod +x "${server_dir}/${APP_NAME}" "${server_dir}/${MCP_NAME}"
|
|
|
[[ -d "${SERVICE_DIR}/cert" ]] && sudo cp -r "${SERVICE_DIR}/cert" "${server_dir}/" || true
|
|
|
[[ -n "${GEN_CONFIG}" ]] && sudo cp "${GEN_CONFIG}" "${server_dir}/config.env" || true
|
|
|
- [[ -n "${GEN_CONFIG}" ]] && sudo cp "${GEN_CONFIG}" "${server_dir}/config.mcp.env" || true
|
|
|
+ if [[ -n "${GEN_MCP_CONFIG}" ]]; then
|
|
|
+ sudo cp "${GEN_MCP_CONFIG}" "${server_dir}/config.mcp.env" || true
|
|
|
+ elif [[ -n "${GEN_CONFIG}" ]]; then
|
|
|
+ sudo cp "${GEN_CONFIG}" "${server_dir}/config.mcp.env" || true
|
|
|
+ fi
|
|
|
fi
|
|
|
|
|
|
# 写入 systemd 服务
|
|
|
@@ -609,6 +752,7 @@ step_frontend() {
|
|
|
# ---------------------------------------------------------------------------
|
|
|
cleanup() {
|
|
|
[[ -n "${GEN_CONFIG}" && -f "${GEN_CONFIG}" ]] && rm -f "${GEN_CONFIG}"
|
|
|
+ [[ -n "${GEN_MCP_CONFIG}" && -f "${GEN_MCP_CONFIG}" ]] && rm -f "${GEN_MCP_CONFIG}"
|
|
|
if [[ "${MODE}" == "remote" ]]; then
|
|
|
ssh_run "rm -rf ${REMOTE_STAGE}" >/dev/null 2>&1 || true
|
|
|
fi
|
|
|
@@ -619,12 +763,12 @@ summary() {
|
|
|
echo "模式 : ${MODE}"
|
|
|
[[ "${MODE}" == "remote" ]] && echo "远程主机 : ${R_USER}@${R_HOST}:${R_PORT}"
|
|
|
echo "部署根目录 : ${DEPLOY_ROOT}"
|
|
|
- echo "已执行步骤 : $( [[ ${DO_DEPS} == y ]] && echo -n '依赖 ' )$( [[ ${DO_CASDOOR} == y ]] && echo -n 'Casdoor ' )$( [[ ${DO_INITDB} == y ]] && echo -n '初始化DB ' )$( [[ ${DO_BACKEND} == y ]] && echo -n '后端 ' )$( [[ ${DO_FRONTEND} == y ]] && echo -n '前端 ' )$( [[ ${DO_CADDY} == y ]] && echo -n 'Caddy ' )$( [[ ${DO_KIRO} == y ]] && echo -n 'KiroCLI ' )"
|
|
|
+ echo "已执行步骤 : $( [[ ${DO_DEPS} == y ]] && echo -n '依赖 ' )$( [[ ${DO_CASDOOR} == y ]] && echo -n 'Casdoor ' )$( [[ ${DO_INITDB} == y ]] && echo -n '初始化DB ' )$( [[ ${DO_BACKEND} == y ]] && echo -n '后端 ' )$( [[ ${DO_FRONTEND} == y ]] && echo -n '前端 ' )$( [[ ${DO_CADDY} == y ]] && echo -n 'Caddy ' )$( [[ ${DO_KIRO} == y ]] && echo -n 'KiroCLI ' )$( [[ ${DO_PGADMIN} == y ]] && echo -n 'pgAdmin4 ' )$( [[ ${DO_MINIOACCT} == y ]] && echo -n 'MinIO账号 ' )"
|
|
|
echo
|
|
|
echo "后续:"
|
|
|
if [[ "${DO_CADDY}" == "y" ]]; then
|
|
|
echo " * Caddy 已配置:https://${CADDY_DOMAIN}/fwh-toolbox/ (站点文件 /etc/caddy/sites/fwh-toolbox.caddy)"
|
|
|
- [[ "${CADDY_TLS_MODE}" == "internal" ]] && echo " 注意:TLS=internal 为自签证书,浏览器会告警,生产请改用 acme/manual。"
|
|
|
+ echo " TLS 走 spaceship DNS-01;token 已写入 systemd 服务(/lib/systemd/system/caddy.service,权限 600)。"
|
|
|
else
|
|
|
echo " * 配置并重载反向代理 Caddy(见 deploy/DEPLOYMENT.md 第 9 章)"
|
|
|
fi
|
|
|
@@ -643,6 +787,17 @@ summary() {
|
|
|
fi
|
|
|
echo " 确认 config.env 的 KIRO_RUN_AS_USER=${RUN_USER}、KIRO_HOME=/home/${RUN_USER} 一致,后端方能拉起 AI 对话。"
|
|
|
fi
|
|
|
+ if [[ "${DO_PGADMIN}" == "y" ]]; then
|
|
|
+ echo " * pgAdmin4 已部署:http://${PGADMIN_BIND}:${PGADMIN_PORT}(登录 ${PGADMIN_EMAIL})"
|
|
|
+ echo " 新建 Server 连本机 PG:主机 host.docker.internal、端口 ${PG_PORT}、用户 postgres。"
|
|
|
+ echo " 若连接报认证失败,多为 pg_hba.conf 未启用 scram-sha-256,见脚本提示。"
|
|
|
+ echo " 安全:勿把 ${PGADMIN_PORT} 暴露公网,建议置于反向代理 + 访问控制之后。"
|
|
|
+ fi
|
|
|
+ if [[ "${DO_MINIOACCT}" == "y" ]]; then
|
|
|
+ echo " * MinIO 业务账号已创建:后端 ${MINIO_ACCESS_KEY:-fwh-toolbox}(写 fwh-toolbox* 桶)、"
|
|
|
+ echo " MCP ${MINIO_AI_ACCESS_KEY}(写 fwh-toolbox-ai* 桶,其余只读)。"
|
|
|
+ echo " 确认 config.env 用后端账号、config.mcp.env 用 AI 账号;核对:mc admin user list fwhlocal"
|
|
|
+ fi
|
|
|
echo " * 验证:curl http://127.0.0.1:${APP_PORT}/swagger/index.html"
|
|
|
if [[ "${MODE}" == "remote" ]]; then
|
|
|
echo " * 查看后端日志:ssh ${R_USER}@${R_HOST} 'journalctl -u ${APP_NAME} -f'"
|
|
|
@@ -687,7 +842,7 @@ main() {
|
|
|
|
|
|
title "确认"
|
|
|
echo "模式=${MODE} 目录=${DEPLOY_ROOT} 运行用户=${RUN_USER}"
|
|
|
- echo "步骤:deps=${DO_DEPS} casdoor=${DO_CASDOOR} initdb=${DO_INITDB} backend=${DO_BACKEND} frontend=${DO_FRONTEND} genconf=${DO_GENCONF} caddy=${DO_CADDY} kiro=${DO_KIRO}"
|
|
|
+ echo "步骤:deps=${DO_DEPS} casdoor=${DO_CASDOOR} initdb=${DO_INITDB} backend=${DO_BACKEND} frontend=${DO_FRONTEND} genconf=${DO_GENCONF} caddy=${DO_CADDY} kiro=${DO_KIRO} pgadmin=${DO_PGADMIN} minio-acct=${DO_MINIOACCT}"
|
|
|
ask_yn "确认开始执行?" "y" || { warn "已取消"; exit 0; }
|
|
|
|
|
|
generate_config
|
|
|
@@ -697,6 +852,8 @@ main() {
|
|
|
step_deps
|
|
|
step_casdoor
|
|
|
step_initdb
|
|
|
+ step_minioacct
|
|
|
+ step_pgadmin
|
|
|
step_backend
|
|
|
step_frontend
|
|
|
step_caddy
|