582 lines
30 KiB
Markdown
582 lines
30 KiB
Markdown
# 测试服务器 Docker 部署手册
|
||
|
||
| 项 | 约定 |
|
||
| --- | --- |
|
||
| 目标服务器目录 | /home/firee-safety-ymd |
|
||
| 运行方式 | 宿主机 Nginx 终止 HTTPS,Docker Compose 运行单个 Go 服务 |
|
||
| 应用监听边界 | 容器内监听 8080,只发布到宿主机 127.0.0.1:16587 |
|
||
| 数据库 | 使用现有 PostgreSQL/PostGIS;本手册不创建数据库容器、不导入 SQL |
|
||
| 状态 | 测试环境部署基线;目标机镜像构建和 Nginx 语法检查已由现场截图证明通过,但容器稳定运行、页面资源、公网 TLS 和 SuperAgent MCP 完整工具链仍待重测 |
|
||
|
||
本手册不包含真实 Token、API Key、数据库密码或旧 Nginx 配置内容。命令中的尖括号是服务器上需要替换的占位符;不要把 Secret 写进命令行、Nginx 文件、镜像构建参数或 Git。
|
||
|
||
## 1. 部署前提
|
||
|
||
本仓库已有可由服务器获取的 `main` 分支。后续部署仍必须由项目维护者先审阅本地变更、手动 commit 并 push 到远程仓库;本项目不会自动提交、推送或迁移服务器数据。以下命令以发布 `main` 分支为例。
|
||
|
||
在开发机提交前先检查暂存区,不要把 `.env` 或被忽略的原始 SQL 强制加入 Git:
|
||
|
||
~~~bash
|
||
cd /Users/andy/IdeaProjects/fire-safety-ymd
|
||
git status --short
|
||
git diff --cached --stat
|
||
# 审阅后通过 IDE 或逐项执行 git add,只暂存确定要发布的路径。
|
||
git commit
|
||
git push -u origin main
|
||
~~~
|
||
|
||
服务器需要具备:
|
||
|
||
- Git、Docker Engine 和 Docker Compose v2(命令为 docker compose)。
|
||
- 宿主机 Nginx、可由 Nginx 读取的 agent.nianxx.com 证书和私钥。
|
||
- 到 PostgreSQL/PostGIS 的网络访问;数据库账号应为运行时只读账号。
|
||
- 如由 SuperAgent 访问 MCP,防火墙、安全组和 TLS 必须允许按约定访问 443。
|
||
|
||
先确认工具版本,不要把配置文件内容打印到日志:
|
||
|
||
~~~bash
|
||
git --version
|
||
docker --version
|
||
docker compose version
|
||
nginx -v
|
||
~~~
|
||
|
||
如果 Nginx 尚未安装,可按发行版选择一种方式;用户已安装时跳过:
|
||
|
||
~~~bash
|
||
# Debian/Ubuntu
|
||
sudo apt-get update
|
||
sudo apt-get install -y nginx
|
||
~~~
|
||
|
||
~~~bash
|
||
# RHEL/CentOS/Fedora 系
|
||
sudo dnf install -y nginx
|
||
~~~
|
||
|
||
安装后确认服务:
|
||
|
||
~~~bash
|
||
sudo systemctl enable --now nginx
|
||
sudo systemctl status nginx --no-pager
|
||
~~~
|
||
|
||
## 2. 获取代码到 /home/firee-safety-ymd
|
||
|
||
### 首次部署
|
||
|
||
维护者完成 commit/push 后,在服务器上执行。私有仓库使用服务器已有的 Git 凭证管理方式,不要把 Git 密码或 Token 写入命令:
|
||
|
||
~~~bash
|
||
sudo mkdir -p /home/firee-safety-ymd
|
||
sudo chown "$(id -un):$(id -gn)" /home/firee-safety-ymd
|
||
git clone https://git.nianxx.cn/huangting/fire-safety-ymd.git /home/firee-safety-ymd
|
||
cd /home/firee-safety-ymd
|
||
git switch main
|
||
~~~
|
||
|
||
如果目录已经是本仓库的工作副本,先确认远程、分支和工作树,再只做快进更新:
|
||
|
||
~~~bash
|
||
cd /home/firee-safety-ymd
|
||
git remote -v
|
||
git status --short
|
||
git fetch --prune origin
|
||
git switch main
|
||
git pull --ff-only origin main
|
||
~~~
|
||
|
||
若 git status --short 有服务器本地改动,先确认归属;不要用 git reset --hard 或覆盖本地文件排障。
|
||
|
||
## 3. 创建服务器 .env
|
||
|
||
.env.example 只是字段说明,不能作为运行时 Secret 文件。首次部署时复制并收紧权限:
|
||
|
||
~~~bash
|
||
cd /home/firee-safety-ymd
|
||
cp .env.example .env
|
||
chmod 600 .env
|
||
~~~
|
||
|
||
用服务器上的受保护编辑器填写 .env,至少确认以下值。三个凭证必须分别生成,不能相互复用:
|
||
|
||
~~~text
|
||
FIRE_SAFETY_HTTP_ADDR=:8080
|
||
# Build-time only. Keep the official default unless the target server cannot
|
||
# reach it; this value is not passed to the running application container.
|
||
FIRE_SAFETY_BUILD_GOPROXY=https://proxy.golang.org,direct
|
||
|
||
FIRE_SAFETY_SUPERAGENT_ENABLED=true
|
||
FIRE_SAFETY_SUPERAGENT_BASE_URL=https://<superagent-api-host>
|
||
FIRE_SAFETY_SUPERAGENT_OPEN_API_KEY=<superagent-open-api-key>
|
||
# 当前外部应用策略关闭 Trace 时保持 false;只有策略显式允许 Trace 才设置 true
|
||
FIRE_SAFETY_SUPERAGENT_INCLUDE_TRACE=false
|
||
|
||
FIRE_SAFETY_CHAT_ENABLED=true
|
||
FIRE_SAFETY_CHAT_AUTH_TOKEN=<独立的高熵xtoken>
|
||
# 新环境必须保持 false;仅当已交付旧客户端的短凭证无法立即更换时,
|
||
# 才能在受控测试/迁移窗口临时设置 true,轮换后恢复 false。
|
||
FIRE_SAFETY_CHAT_ALLOW_LEGACY_SHORT_TOKEN=false
|
||
FIRE_SAFETY_CHAT_SUBJECT_ID=fire-safety-ymd-chat-test-subject
|
||
FIRE_SAFETY_CHAT_COMPAT_APP_ID=<与Nginx路径完全一致的公开app-id>
|
||
# 可选的受控测试页面默认关闭;开启时必须同时启用 Chat/兼容入口
|
||
FIRE_SAFETY_CHAT_PAGE_ENABLED=false
|
||
# 页面从 agent.nianxx.com 同源加载时必须包含该精确 Origin;可按需追加其他测试 Origin
|
||
FIRE_SAFETY_CHAT_ALLOWED_ORIGINS=https://agent.nianxx.com
|
||
|
||
FIRE_SAFETY_MCP_ENABLED=true
|
||
FIRE_SAFETY_MCP_AUTH_TOKEN=<独立的高熵MCP-bearer>
|
||
FIRE_SAFETY_MCP_SCOPE_MODE=all
|
||
FIRE_SAFETY_MCP_ALLOWED_TOWNS=
|
||
|
||
FIRE_SAFETY_POSTGIS_ENABLED=true
|
||
FIRE_SAFETY_POSTGIS_DSN=<只读PostgreSQL连接串>
|
||
FIRE_SAFETY_POSTGIS_MIGRATION_DSN=
|
||
FIRE_SAFETY_POSTGIS_EXPECTED_SRID=4326
|
||
~~~
|
||
|
||
注意:
|
||
|
||
- FIRE_SAFETY_CHAT_AUTH_TOKEN 只用于兼容对话入口的 xtoken;FIRE_SAFETY_MCP_AUTH_TOKEN 只用于 SuperAgent 调用 /mcp;FIRE_SAFETY_SUPERAGENT_OPEN_API_KEY 只用于 Go 服务访问 SuperAgent。三者必须不同。
|
||
- Chat Token 默认至少 32 个可打印 ASCII 字符。如果已交付的旧客户端凭证较短且无法立即更换,只能临时设置 `FIRE_SAFETY_CHAT_ALLOW_LEGACY_SHORT_TOKEN=true`;此时仍要求 Token 非空、不超过 4096 字节,并且每个字符都在 ASCII `0x21-0x7e` 范围内(无空格、控制字符或 Unicode)。该开关只影响 Chat 原生 Bearer 和兼容 `xtoken`,不放宽 MCP Token 至少 32 个可打印 ASCII 字符的要求。新环境不得开启,凭证轮换完成后必须恢复 `false`;开关启用时启动日志会记录不含 Secret 的安全 warning。
|
||
- FIRE_SAFETY_CHAT_COMPAT_APP_ID 是公开路径标识,不是 Secret;它必须与 Nginx 的精确 location = /api/v1/apps/<app-id>/completion 完全一致。
|
||
- FIRE_SAFETY_CHAT_PAGE_ENABLED 默认必须为 false。开启后 Go 提供 `/chat`、`/chat/` 以及同源的
|
||
`/chat/app.css`、`/chat/app.js`;`/chat` 会 308 到 `/chat/`,页面和资源的最终可用性仍由 Go
|
||
开关决定。页面只用于受控测试,不嵌入或持久化 Token。
|
||
- FIRE_SAFETY_SUPERAGENT_INCLUDE_TRACE 默认必须为 false。无 Trace 的严格成功条件是最终 AI 消息
|
||
`finish_reason=stop`、非空顶层 `event: message.final` 加顶层 `event: end`;设置为 true 时还要求
|
||
`run.completed(status=success)`,且外部应用策略必须开启 `trace_policy.enabled=true`。无 Trace
|
||
只是不返回公开工具/步骤轨迹,不等于禁止 SuperAgent 调用 MCP。
|
||
- 页面开启时 FIRE_SAFETY_CHAT_ALLOWED_ORIGINS 必须包含精确的 `https://agent.nianxx.com`,并且
|
||
Chat 兼容 App ID、Chat Token 和 SuperAgent 配置已经可用;该静态页面不是最终用户认证。
|
||
- 使用 FIRE_SAFETY_MCP_SCOPE_MODE=all 时,FIRE_SAFETY_MCP_ALLOWED_TOWNS 必须保持为空。all 是服务账号级的固定查询表范围,不是最终用户级授权。
|
||
- FIRE_SAFETY_POSTGIS_MIGRATION_DSN 不应配置给运行服务;迁移凭证只供一次性迁移命令使用,完成后应移除。
|
||
- FIRE_SAFETY_HTTP_ADDR 在容器内应为 :8080,安全边界由 Compose 的 127.0.0.1:16587:8080 和宿主机 Nginx 提供;不要在 Compose 场景设为容器内的 127.0.0.1:8080。
|
||
- 不要用没有 --quiet 的 docker compose config 或 docker inspect 把完整环境渲染到终端、CI 日志或工单;检查 .env 权限仍为 600。
|
||
- 修改 `.env` 后必须重新创建容器(例如 `docker compose up -d --force-recreate --no-build`)才能加载新的 Chat 兼容开关;单独 `docker compose restart` 不会重新读取容器环境。旧短凭证仅用于受控测试/迁移,完成轮换后把开关改回 `false` 并再次 recreate。
|
||
- 修改 `FIRE_SAFETY_SUPERAGENT_INCLUDE_TRACE` 或其他 SuperAgent 代码/配置后,至少执行
|
||
`docker compose config --quiet`、`docker compose build --pull` 和
|
||
`docker compose up -d --force-recreate --remove-orphans`;仅 `docker compose restart` 不会
|
||
重新读取 `.env`,也不会把新代码构建进镜像。
|
||
|
||
## 4. 容器访问现有 PostgreSQL/PostGIS
|
||
|
||
本项目不在 Compose 中创建或初始化数据库。数据库继续由现有 PostgreSQL/PostGIS 运维,Go 服务只使用已完成 SRID 确认的只读数据源。
|
||
|
||
如果 PostgreSQL 在另一台机器:
|
||
|
||
- DSN 使用数据库私网 DNS 或私网地址,不使用容器内的 127.0.0.1。
|
||
- 数据库防火墙只允许测试服务器访问 5432;如启用 TLS,按数据库证书要求配置 DSN 的 sslmode,不要为了省事关闭证书校验。
|
||
|
||
如果 PostgreSQL 与 Docker 在同一台宿主机:
|
||
|
||
- 容器内的 127.0.0.1 指向容器自身;DSN 使用 Compose 声明的 host.docker.internal(或运维明确提供的 Docker 网关地址)。
|
||
- Linux Compose 需要有 host.docker.internal:host-gateway 映射;本仓库的 Compose 配置包含该映射时才能使用这个名称。
|
||
- PostgreSQL 的 listen_addresses、pg_hba.conf 和主机防火墙只允许 Docker 网段中的只读账号访问,不要发布 5432 到公网。
|
||
- 不要把迁移账号放入 .env;数据库配置变更先由管理员验证最小权限。
|
||
|
||
服务启动时进行 MCP PostGIS readiness 校验。SRID、几何类型或 WGS84 范围硬门禁失败会阻止服务装配;空/无效几何和缺 GiST 索引是当前已知 warning。GET /health 只是进程存活检查,不代表数据库、SuperAgent 或 MCP 已可用,必须同时检查 Compose 日志和实际接口。
|
||
|
||
## 5. 构建、启动和本机检查
|
||
|
||
以下命令在服务器项目目录执行。Compose 构建上下文不复制 `.env`;非 Secret 的 `FIRE_SAFETY_BUILD_GOPROXY` 只会被映射为构建参数,并在运行容器环境中强制清空。
|
||
|
||
先检查 Go 模块代理是否从服务器/Docker 所在网络可达:
|
||
|
||
~~~bash
|
||
curl --head --connect-timeout 10 https://proxy.golang.org/
|
||
~~~
|
||
|
||
如果连接官方代理超时,可以测试经运维认可的替代代理。例如 [Goproxy.cn](https://goproxy.cn/) 官方说明支持标准 Go module proxy 协议:
|
||
|
||
~~~bash
|
||
curl --head --connect-timeout 10 https://goproxy.cn/
|
||
~~~
|
||
|
||
只有确认替代代理可达且组织允许使用时,才在服务器 `.env` 中改为:
|
||
|
||
~~~text
|
||
FIRE_SAFETY_BUILD_GOPROXY=https://goproxy.cn,direct
|
||
~~~
|
||
|
||
该值必须是不含用户名、密码或 Token 的代理地址;Docker build argument 不是 Secret 注入机制。若组织代理要求认证,需要另做 BuildKit Secret 设计,不能把凭证嵌进 URL 或 `.env` 中的构建参数。
|
||
|
||
主机侧 curl 成功只能初步说明连通性;最终仍以 `docker compose build` 是否能下载并校验模块为准。如果两个地址都超时,应修复 Docker/宿主机的 DNS、HTTPS 出口、透明代理或防火墙,或者使用组织自建的可信 Go module proxy。不要设置 `GOSUMDB=off`、跳过 `go.sum` 校验或反复执行 `docker compose up` 掩盖依赖下载失败。
|
||
|
||
代理连通后再构建并启动:
|
||
|
||
~~~bash
|
||
cd /home/firee-safety-ymd
|
||
docker compose config --quiet
|
||
docker compose build --pull
|
||
docker compose up -d
|
||
docker compose ps
|
||
docker compose logs --tail=100 api
|
||
curl --fail http://127.0.0.1:16587/health
|
||
~~~
|
||
|
||
预期结果:容器为 Up(健康状态由 Compose 显示),health 返回 HTTP 200;有限日志不应出现 DSN、密码、Token 或 API Key。docker compose config --quiet 只验证配置,不输出展开后的 Secret。若 Compose 不支持 --quiet,升级 Compose 或使用不会回显结果的等价校验方式。
|
||
|
||
若构建在 `RUN go mod download` 处失败,则镜像和容器尚未生成,后续访问宿主机端口会得到 connection refused。先解决模块代理连通性并重新执行 `docker compose build --pull`,成功后才能执行 `up -d`。
|
||
|
||
失败时只读取有限日志:
|
||
|
||
~~~bash
|
||
docker compose ps
|
||
docker compose logs --tail=200 api
|
||
~~~
|
||
|
||
不要把完整日志粘贴到公共工单;先删去 URL 凭证、连接串、Header、联系人和精确位置。readiness 报错时核对数据库地址、只读权限和 FIRE_SAFETY_POSTGIS_EXPECTED_SRID=4326,不要关闭门禁或修改原始几何。
|
||
|
||
## 6. 安装/替换宿主机 Nginx 配置
|
||
|
||
仓库模板为 deploy/nginx/fire-safety-ymd.conf.example,不含真实 Secret。它把精确 Chat 兼容路径、/mcp 和可选 /health 反代到 127.0.0.1:16587,其他路径返回 404;详细 SSE 边界见 nginx-public-entry.md。
|
||
|
||
先只查找拥有 agent.nianxx.com 的配置文件名,避免使用 nginx -T 把旧文件中的 DashScope Key 打到终端:
|
||
|
||
~~~bash
|
||
sudo grep -RIl \
|
||
'server_name[[:space:]]\+agent\.nianxx\.com' \
|
||
/etc/nginx/conf.d /etc/nginx/sites-enabled 2>/dev/null
|
||
~~~
|
||
|
||
旧配置迁移前:
|
||
|
||
1. 记录旧配置文件路径和归属;不要把旧配置内容复制到仓库或新模板。
|
||
2. 如需回滚,将旧文件以 root 权限备份到不被 Nginx include 的目录并限制为 600;若含真实 DashScope Key,应由凭证所有者安排轮换。
|
||
3. 把旧文件移出 *.conf include(例如改为 .disabled),避免同一域名出现两个冲突的 server 块。移动前确认目标是上一步查到的精确路径,不要批量操作整个 /etc/nginx。
|
||
|
||
部署模板的示例(目录因发行版而异;使用 sites-enabled 时按实际 include 位置调整):
|
||
|
||
~~~bash
|
||
sudo install -o root -g root -m 0644 \
|
||
deploy/nginx/fire-safety-ymd.conf.example \
|
||
/etc/nginx/conf.d/fire-safety-ymd.conf
|
||
sudo vi /etc/nginx/conf.d/fire-safety-ymd.conf
|
||
~~~
|
||
|
||
编辑时完成以下非 Secret 替换:
|
||
|
||
- 将 replace-with-fire-safety-app-id 替换为 .env 中的 FIRE_SAFETY_CHAT_COMPAT_APP_ID。
|
||
- 确认证书路径、域名和上游 127.0.0.1:16587 符合测试服务器。
|
||
- 保留精确 location、SSE 的 proxy_buffering off/超时设置和其他路径的 404;不要恢复旧配置的 location /、DashScope proxy_pass、Authorization Key 或 Nginx if Token 比较。
|
||
- limit_req_zone 必须位于 Nginx http 上下文;模板假定由 conf.d/*.conf 在 http {} 中 include。若 include 层级不同,把指令移到合法的 http 上下文。
|
||
|
||
确认旧配置已禁用且新文件不含 Secret 后,再验证并 reload:
|
||
|
||
~~~bash
|
||
sudo nginx -t
|
||
sudo systemctl reload nginx
|
||
~~~
|
||
|
||
如果 Nginx 不由 systemd 管理,使用发行版的 reload 方式;reload 前必须先通过 nginx -t。
|
||
|
||
## 7. 公网 Chat SSE 冒烟
|
||
|
||
先验证宿主机本地 /health 和 HTTPS /health,再用不含敏感信息的问题验证 SSE。将 Token 安全注入当前 shell(例如受保护的 Secret 管理器或交互式读取),不要把字面量写入 shell 历史:
|
||
|
||
~~~bash
|
||
read -rsp 'Chat xtoken: ' CHAT_XTOKEN
|
||
printf '\n'
|
||
~~~
|
||
|
||
首轮请求:
|
||
|
||
~~~bash
|
||
curl -N --fail \
|
||
-H "xtoken: $CHAT_XTOKEN" \
|
||
-H 'Content-Type: application/json' \
|
||
-H 'Accept: text/event-stream' \
|
||
--data '{"input":{"prompt":"观水镇附近有哪些水源候选?"},"parameters":{}}' \
|
||
'https://agent.nianxx.com/api/v1/apps/<same-safe-app-id>/completion'
|
||
~~~
|
||
|
||
确认能读取 event: result,最后一个成功事件的 output.finish_reason 为 stop。只有 stop 事件的 output.text 可当作完成;中途断流、HTTP 错误或只有 finish_reason=null 不得当作可信答案。output.session_id 是本项目本地会话 ID,不是 SuperAgent 内部 Session ID。
|
||
|
||
后续轮次使用上一轮成功返回的本地会话 ID:
|
||
|
||
~~~bash
|
||
curl -N --fail \
|
||
-H "xtoken: $CHAT_XTOKEN" \
|
||
-H 'Content-Type: application/json' \
|
||
-H 'Accept: text/event-stream' \
|
||
--data '{"input":{"prompt":"再说明候选的限制","session_id":"<session-id-from-previous-response>"},"parameters":{}}' \
|
||
'https://agent.nianxx.com/api/v1/apps/<same-safe-app-id>/completion'
|
||
~~~
|
||
|
||
至少验证:错误 xtoken 为 401;不存在的 app ID 和未列出的路径为 404。不要使用真实联系人、电话或精确敏感位置作为冒烟问题。
|
||
|
||
完成 Chat 测试后清理当前 shell 中的临时变量:
|
||
|
||
~~~bash
|
||
unset CHAT_XTOKEN
|
||
~~~
|
||
|
||
## 8. 公网 Chat 测试页面
|
||
|
||
测试页面由 Go 可选提供,不需要单独的前端容器或 Nginx 静态目录。页面及两个同源资源的
|
||
Nginx 精确路径已经包含在仓库模板中:`/chat`、`/chat/`、`/chat/app.css` 和 `/chat/app.js`。
|
||
Nginx 始终可以反代这些路径,但是否返回内容由 Go 的
|
||
`FIRE_SAFETY_CHAT_PAGE_ENABLED` 控制。
|
||
|
||
### 开启页面
|
||
|
||
在服务器受保护的 `.env` 中确认或修改以下非 Secret 配置:
|
||
|
||
~~~text
|
||
FIRE_SAFETY_CHAT_ENABLED=true
|
||
FIRE_SAFETY_CHAT_COMPAT_APP_ID=<与Nginx completion路径一致的公开app-id>
|
||
FIRE_SAFETY_CHAT_PAGE_ENABLED=true
|
||
FIRE_SAFETY_CHAT_ALLOWED_ORIGINS=https://agent.nianxx.com
|
||
~~~
|
||
|
||
页面开启要求 Chat、兼容 App ID、Chat 测试凭证和 SuperAgent 配置已经有效;
|
||
`https://agent.nianxx.com` 必须是精确 Origin,不能使用 `*`。页面是受控测试工具,不是最终
|
||
用户认证,用户要在页面中手动输入 xtoken,不能把 Token 写入页面、Nginx 或镜像。
|
||
|
||
修改 `.env` 后必须重新创建容器,单独 restart 不会重新读取环境变量:
|
||
|
||
~~~bash
|
||
cd /home/firee-safety-ymd
|
||
docker compose config --quiet
|
||
docker compose up -d --force-recreate --no-build
|
||
docker compose ps
|
||
curl --fail http://127.0.0.1:16587/health
|
||
~~~
|
||
|
||
如果 Nginx 模板刚刚更新,再执行 `sudo nginx -t`,确认通过后再 reload;只改 Go 开关时不需要
|
||
改 Nginx 文件。
|
||
|
||
### 页面验收
|
||
|
||
先不带 Token 检查页面和资源路由:
|
||
|
||
~~~bash
|
||
curl -i https://agent.nianxx.com/chat
|
||
curl -i https://agent.nianxx.com/chat/
|
||
curl -i https://agent.nianxx.com/chat/app.css
|
||
curl -i https://agent.nianxx.com/chat/app.js
|
||
~~~
|
||
|
||
开启时预期 `/chat` 返回 HTTP 308 并指向 `/chat/`,`/chat/` 返回 HTTP 200 HTML,CSS 和
|
||
JavaScript 返回 HTTP 200。需要自动跟随入口重定向时使用:
|
||
|
||
~~~bash
|
||
curl -iL https://agent.nianxx.com/chat
|
||
~~~
|
||
|
||
关闭时,Go 不注册页面 Handler,`/chat`、`/chat/`、`/chat/app.css` 和 `/chat/app.js` 均
|
||
直接返回 HTTP 404;这与 Nginx 是否保留四个精确 location 无关。
|
||
|
||
浏览器打开 `https://agent.nianxx.com/chat/`,手动输入受控测试 xtoken(页面不会预填或保存),
|
||
发送不含敏感信息的问题。Network 面板应看到同源 POST 到
|
||
`/api/v1/apps/<same-safe-app-id>/completion`,请求体为第三方兼容格式,Header 含 `xtoken`,
|
||
响应为 `event: result` SSE。只有 `output.finish_reason=stop` 才是成功;第二轮请求应把第一轮
|
||
成功返回的 `output.session_id` 放入 `input.session_id`。刷新或关闭页面后,Token 和 session_id
|
||
均应清除,不得自动恢复。
|
||
|
||
### 关闭与回滚
|
||
|
||
紧急关闭页面时,将 `.env` 的 `FIRE_SAFETY_CHAT_PAGE_ENABLED` 改回 `false`,执行:
|
||
|
||
~~~bash
|
||
cd /home/firee-safety-ymd
|
||
docker compose up -d --force-recreate --no-build
|
||
curl -i https://agent.nianxx.com/chat
|
||
curl -i https://agent.nianxx.com/chat/
|
||
~~~
|
||
|
||
确认两个路径直接 404(无 308),并按需检查 CSS/JavaScript 资源也为 404。该操作不会自动
|
||
关闭兼容 completion;如需一并关闭 Chat,再按 Chat 总开关执行配置回滚。若页面版本或 Nginx
|
||
版本导致故障,回到维护者指定的已验证 Git revision 或 root-only Nginx 备份,先 `nginx -t`
|
||
再 reload;不要恢复旧的全路径 DashScope 代理、关闭 Go 鉴权或把 Secret 写入 Nginx。
|
||
|
||
## 9. SuperAgent Open API 无 Trace 模式
|
||
|
||
当前测试环境优先使用无 Trace 模式,避免外部应用策略未开放公开 Trace 导致消息流返回
|
||
`HTTP 403` / `open_agent_trace_disabled`。在服务器 `.env` 中确认:
|
||
|
||
~~~text
|
||
FIRE_SAFETY_SUPERAGENT_INCLUDE_TRACE=false
|
||
~~~
|
||
|
||
无 Trace 模式仍严格要求上游最终 AI 消息的 `finish_reason=stop`、非空顶层
|
||
`event: message.final` 和顶层 `event: end`;最终回答只取 `message.final.text`。它只是不向调用方
|
||
返回公开工具/步骤轨迹,不等于禁止 SuperAgent 在执行中调用已配置的 MCP 工具。确认 MCP 是否
|
||
实际被调用,必须检查 `/mcp` 日志和返回结果。只有外部应用策略显式开启
|
||
`trace_policy.enabled=true` 时,才把该值改为 `true`;Trace 模式会额外要求
|
||
`run.completed(status=success)`。
|
||
|
||
修改 `.env` 后必须重新构建并重新创建服务,使配置在运行容器中生效:
|
||
|
||
~~~bash
|
||
cd /home/firee-safety-ymd
|
||
docker compose config --quiet
|
||
docker compose build --pull
|
||
docker compose up -d --force-recreate --remove-orphans
|
||
docker compose ps
|
||
docker compose logs --tail=100 api
|
||
curl --fail http://127.0.0.1:16587/health
|
||
~~~
|
||
|
||
不要在日志或工单中粘贴 Open API Key。若仍收到 403,只记录 HTTP 状态、脱敏后的 Provider code、
|
||
时间和请求关联 ID,交由 SuperAgent 平台核对外部应用策略;不要反复轮换无关的 Chat/MCP 凭证。
|
||
|
||
受控诊断已经确认:同一 Key 的 `include_trace=true` 因应用策略返回 403
|
||
`open_agent_trace_disabled`;同一 Key 的 `include_trace=false` 已由真实探针完成严格成功判定,
|
||
本地兼容 Chat SSE 也完成 `finish_reason=null -> stop`。公网完整消防对话、MCP 实际工具调用和
|
||
多轮会话仍需单独验收。
|
||
|
||
## 10. SuperAgent MCP 回调配置与冒烟
|
||
|
||
在 SuperAgent 的工具/MCP 配置中新增远程 MCP 服务:
|
||
|
||
~~~text
|
||
URL: https://agent.nianxx.com/mcp
|
||
Method: POST
|
||
Authorization: Bearer <FIRE_SAFETY_MCP_AUTH_TOKEN>
|
||
~~~
|
||
|
||
该 Bearer 必须是 .env 中独立的 FIRE_SAFETY_MCP_AUTH_TOKEN,不要填 Chat xtoken 或 SuperAgent Open API Key。SuperAgent 当前不能在配置中指定 `protocolVersion`;不要把它或 `MCP-Protocol-Version` 作为客户端配置项加入。已稳定接通的 `th-hotel-simple-superagent` 不读取或校验这些版本元数据,而是固定返回 `2025-06-18`;消防 MCP 按这一已验证兼容档案接入,目标是打通工具调用,不是追求最新协议。SuperAgent 还可能需要公网来源 IP 白名单、TLS CA 或其他平台级 Header,按实际平台和网络策略确认。
|
||
|
||
服务端兼容规则如下:对可解析的 JSON-RPC `initialize`,`params.protocolVersion` 的缺失、空值、非字符串或其他值都不作为版本拒绝条件,响应固定返回 `result.protocolVersion: "2025-06-18"`;`MCP-Protocol-Version` Header 的缺失或值也不作为版本拒绝条件。固定返回该版本不表示服务实现或声明支持任意客户端版本,`2025-03-26`、`2025-11-25` 等值也不改变服务端实现目标。兼容仅针对版本元数据,Bearer、`Content-Type`、非空 `Origin`、JSON-RPC 结构、只读工具、服务端数据范围和敏感字段边界仍严格执行。
|
||
|
||
现场日志已证明公网 `/mcp` 完成 initialize、notifications/initialized、tools/list,并成功调用一次 `fire_safety_search_place_candidates`;该证据只覆盖地点搜索,不能替代其余消防工具和完整多工具链验收。同一 SuperAgent 中 `th-hotel-simple-superagent` 已稳定调用是兼容档案参照。部署后继续通过 `direct_success`(客户端值为 `2025-06-18`)或 `compatibility_success`(版本字段缺失或其他值被兼容处理)日志分类确认,服务端不得记录原始版本值。
|
||
|
||
如果修改了 MCP Handler 或握手协商逻辑,目标机必须拉取包含该修改的明确 revision 后重建镜像;仅 `docker compose restart` 不会更新镜像中的代码:
|
||
|
||
~~~bash
|
||
cd /home/firee-safety-ymd
|
||
git fetch --prune origin
|
||
git switch main
|
||
git pull --ff-only origin main
|
||
docker compose config --quiet
|
||
docker compose build --pull
|
||
docker compose up -d --force-recreate --remove-orphans
|
||
docker compose ps
|
||
docker compose logs --tail=100 api
|
||
curl --fail http://127.0.0.1:16587/health
|
||
~~~
|
||
|
||
在服务器或受控终端用独立变量测试初始化。下面的版本字段只是普通 JSON-RPC 参数示例,SuperAgent 不需要配置它;也可以省略或使用客户端实际发送的值:
|
||
|
||
~~~bash
|
||
read -rsp 'MCP bearer: ' MCP_BEARER
|
||
printf '\n'
|
||
curl --fail \
|
||
-H "Authorization: Bearer $MCP_BEARER" \
|
||
-H 'Content-Type: application/json' \
|
||
-H 'Accept: application/json, text/event-stream' \
|
||
--data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"manual-probe","version":"1"}}}' \
|
||
'https://agent.nianxx.com/mcp'
|
||
|
||
curl --fail --output /dev/null --write-out 'initialized HTTP %{http_code}\n' \
|
||
-H "Authorization: Bearer $MCP_BEARER" \
|
||
-H 'Content-Type: application/json' \
|
||
-H 'Accept: application/json, text/event-stream' \
|
||
--data '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
|
||
'https://agent.nianxx.com/mcp'
|
||
|
||
curl --fail \
|
||
-H "Authorization: Bearer $MCP_BEARER" \
|
||
-H 'Content-Type: application/json' \
|
||
-H 'Accept: application/json, text/event-stream' \
|
||
--data '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
|
||
'https://agent.nianxx.com/mcp'
|
||
|
||
curl --fail \
|
||
-H "Authorization: Bearer $MCP_BEARER" \
|
||
-H 'Content-Type: application/json' \
|
||
-H 'Accept: application/json, text/event-stream' \
|
||
--data '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"fire_safety_search_place_candidates","arguments":{"place_name":"观水镇","limit":3}}}' \
|
||
'https://agent.nianxx.com/mcp'
|
||
~~~
|
||
|
||
确认第一步固定返回 `result.protocolVersion: 2025-06-18`,第二步返回 HTTP 202,第三步列出 7 个固定工具,第四步至少完成一个受控只读 `tools/call`。这四步 `initialize` → `notifications/initialized` → `tools/list` → `tools/call` 才是 SuperAgent 能调用消防 MCP 的验收链路;只看到 initialize 成功不能宣称接通。版本 Header 不需要配置或继续携带。再用无敏感信息的已知地名/点位做少量只读调用,核对正确 Bearer 成功、错误/缺失 Bearer 为 401、warnings 保留、非法参数不会变成任意 SQL。查询到资源记录不代表实时可用、路线已规划或正式集结点。
|
||
|
||
完成 MCP 测试后清理当前 shell 中的临时变量:
|
||
|
||
~~~bash
|
||
unset MCP_BEARER
|
||
~~~
|
||
|
||
## 11. 更新、重启与回滚
|
||
|
||
### 发布新版本
|
||
|
||
维护者先将目标版本 commit/push 后,服务器快进更新并重建:
|
||
|
||
~~~bash
|
||
cd /home/firee-safety-ymd
|
||
git fetch --prune origin
|
||
git switch main
|
||
git pull --ff-only origin main
|
||
docker compose config --quiet
|
||
docker compose build --pull
|
||
docker compose up -d --remove-orphans
|
||
docker compose ps
|
||
docker compose logs --tail=100 api
|
||
~~~
|
||
|
||
更新会重启单个 Go 进程,现有内存会话丢失;客户端按会话失效处理并重新开始对话。当前部署不支持多实例共享会话,也没有持久化历史或审计。
|
||
|
||
### 回滚
|
||
|
||
回滚到上一个已验证的 Git commit 或镜像版本。先保留现状信息并确认目标版本;不要用破坏性 reset 覆盖未知的服务器本地改动:
|
||
|
||
~~~bash
|
||
cd /home/firee-safety-ymd
|
||
git status --short
|
||
git log --oneline -5
|
||
~~~
|
||
|
||
由维护者确认目标 commit(例如 `<verified-commit>`)后,先以 detached HEAD 检出该已验证版本,再重新构建启动;这是显式回滚,不会自动覆盖服务器本地改动:
|
||
|
||
~~~bash
|
||
git fetch --prune origin
|
||
git switch --detach <verified-commit>
|
||
docker compose build --pull
|
||
docker compose up -d --remove-orphans
|
||
docker compose ps
|
||
~~~
|
||
|
||
回滚结束并准备恢复正常发布轨道时,再切回维护者指定的分支:
|
||
|
||
~~~bash
|
||
git switch main
|
||
git pull --ff-only origin main
|
||
~~~
|
||
|
||
如果是 Nginx 配置导致故障,先恢复 root-only 备份,确认旧域名配置没有重复 include,再执行:
|
||
|
||
~~~bash
|
||
sudo nginx -t
|
||
sudo systemctl reload nginx
|
||
~~~
|
||
|
||
回滚后重新检查本机和公网 /health、Chat 401/404 边界以及 MCP 初始化。docker compose down 只停止容器,不删除代码或数据库;明确需要停服时再执行:
|
||
|
||
~~~bash
|
||
cd /home/firee-safety-ymd
|
||
docker compose down
|
||
~~~
|
||
|
||
## 12. 完成判定与当前限制
|
||
|
||
本手册完成不代表公网部署已完成。现场交付至少应记录:
|
||
|
||
- 目标机 Compose 配置校验、build、up、健康检查和无 Secret 的有限日志结果。
|
||
- 目标机 nginx -t 和 reload 成功;443 证书、DNS、安全组及旧 location / 已确认不再生效。
|
||
- 页面开关关闭时 `/chat`、`/chat/`、`/chat/app.css`、`/chat/app.js` 直接返回 404;开启时 `/chat` 返回 308、`/chat/` 返回 200 HTML,两个资源返回 200;`FIRE_SAFETY_CHAT_ALLOWED_ORIGINS` 包含 `https://agent.nianxx.com`。
|
||
- Chat 首轮/多轮 SSE、错误凭证、未知 app/path 的实际 HTTPS 响应。
|
||
- 页面浏览器验收证明用户手动输入 xtoken、Token 不被页面持久化、兼容 completion SSE 及同页面 `session_id` 复用;这只是静态测试页面,不是生产认证。
|
||
- 若为已交付旧客户端临时开启 Chat legacy 短凭证兼容,应记录受控迁移窗口,确认启动 warning 不含 Secret,并在凭证轮换后恢复 `FIRE_SAFETY_CHAT_ALLOW_LEGACY_SHORT_TOKEN=false`。
|
||
- SuperAgent Open API 使用 `FIRE_SAFETY_SUPERAGENT_INCLUDE_TRACE=false` 时,验证最终 AI 消息
|
||
`finish_reason=stop`、非空顶层 `message.final` 加顶层 `end`;若切换为 true,验证外部应用
|
||
Trace 策略已开启且 `run.completed(status=success)` 仍为必要条件。无 Trace 不等同于 MCP
|
||
禁用;完整消防对话和 MCP 工具调用仍须单独记录。
|
||
- SuperAgent -> `/mcp` 的独立 Bearer、TLS/网络白名单、无版本配置 initialize 兼容响应、`notifications/initialized`、`tools/list` 和全部 7 个受控只读 `tools/call`。现场已有地点搜索一次成功证据,但其余工具未验收;版本字段/Header 不作为配置或拒绝门禁;公网请求到达但没有完成这条调用链,不算完成。
|
||
- 数据库未公开 5432,运行账号保持只读,PostGIS readiness warning 和 35 条无效面几何缺口已记录。
|
||
|
||
若目标服务器无法使用 host.docker.internal、Compose 不支持 --quiet、Nginx include 目录不同、证书路径不同或 SuperAgent 对 MCP 的认证格式不同,应先记录实际环境并调整部署 Spec;不要通过放开端口、写入 Token、关闭 readiness 或恢复全路径反代规避问题。
|