feat(agent): 默认回环监听并自动建立 SSH 隧道并发布 v1.4.0
This commit is contained in:
+2
-1
@@ -1,7 +1,7 @@
|
||||
# Fonu 文档索引
|
||||
|
||||
> 维护约定:新增方案 / 审查文档时在下方登记;方案落地后在「状态」列标注实施结果,并给已被推翻的描述加时效说明。
|
||||
> 最近更新:2026-09-28(v1.3.9)
|
||||
> 最近更新:2026-09-28(v1.4.0)
|
||||
|
||||
## 方案与设计(本目录)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
| `project-analysis-2026-09-27.md` | 全项目详细分析(v1.2.19):架构、模块、数据、API、前端、链路、风险与改进路线 | 当前版本快照 |
|
||||
| `improvement-roadmap-2026-09-27.md` | P0-P3 改进路线实施方案:逐项改法、测试、验收、依赖、发布与回滚 | P0-1、P0-3、P0-4 已完成,其余待实施 |
|
||||
| `system-upgrade.md` | Docker Compose 一键升级:sidecar 架构、首次部署、安全边界、回滚、故障排查与验证页 | 已实施(v1.3.8) |
|
||||
| `agent-listen-strategy-plan.md` | Agent 默认监听策略:回环监听、SSH 隧道优先、HTTPS pin 可选与自动迁移方案 | 核心自动隧道已实施(v1.4.0);HTTPS pin 高级模式待后续 |
|
||||
| `project-audit-2026-09-24.md` | 全项目审查:P0/P1/P2 分级,含精确行号与逐条修法 | **进行中**——P0 已随 v1.2.7 完成,P1 实施中 |
|
||||
| `frp-server-list-merge-plan.md` | FRP 服务端列表并入「公网服务端」页(方案 A,四步) | 步 1/2 已完成(v1.2.6);步 3 文案收尾、步 4 死样式清理未做 |
|
||||
| `agent-capability-plan.md` | fonu-agent 能力扩展(P0/P1/P2/P3) | 已实施(agent 0.11.0);P3 三项不做 |
|
||||
|
||||
@@ -0,0 +1,755 @@
|
||||
# Agent 默认监听策略与自动安全接入方案
|
||||
|
||||
> 方案编号:P0-5
|
||||
> 制定日期:2026-09-28
|
||||
> 当前 AgentVersion:0.13.0
|
||||
> 目标:默认不暴露 Agent 管理接口,安装和升级过程自动建立安全连接,不要求用户手工配置端口、隧道或证书
|
||||
|
||||
> 实施状态(2026-09-28):阶段 1-3 的自动 SSH 隧道核心已随 v1.4.0 实施;HTTPS + pin 高级模式与防火墙辅助仍按阶段 4-5 推进。
|
||||
|
||||
---
|
||||
|
||||
## 一、结论
|
||||
|
||||
推荐采用**自动为主、安全优先、旧模式显式兼容**的三层策略:
|
||||
|
||||
1. **默认模式:SSH 隧道 + 回环监听**
|
||||
- `fonu-agent` 默认只监听 `127.0.0.1:7700`。
|
||||
- 中央 Fonu 使用现有 SSH 凭据建立本地转发:
|
||||
|
||||
```text
|
||||
中央 Fonu 127.0.0.1:<随机本地端口>
|
||||
→ SSH 加密连接
|
||||
→ VPS 127.0.0.1:7700
|
||||
→ fonu-agent
|
||||
```
|
||||
|
||||
- 不开放公网 Agent 端口,不需要域名、证书、云安全组或防火墙修改。
|
||||
|
||||
2. **可选模式:自动 HTTPS 反代 + 证书固定**
|
||||
- Agent 仍只监听回环地址。
|
||||
- HTTPS 不作为首次安装选项;Agent 安全安装完成后,用户可在「公网 Agent」页切换到该高级模式。
|
||||
- 切换时自动配置 Nginx HTTPS 反代,并使用自签名证书。
|
||||
- 中央 Fonu 首次安装时记录证书指纹,后续按指纹校验。
|
||||
- 适用于希望免维护常驻 SSH 隧道、且愿意开放一个 HTTPS 端口的用户。
|
||||
|
||||
3. **兼容模式:显式公网明文 HTTP**
|
||||
- 保留旧部署能力,但必须显式开启。
|
||||
- UI 持续显示高危警告。
|
||||
- 不允许自动降级到该模式。
|
||||
|
||||
默认安装与升级过程不需要用户设置 `FONU_AGENT_LISTEN`、TLS 证书或防火墙规则。
|
||||
|
||||
---
|
||||
|
||||
## 二、现状
|
||||
|
||||
### 2.1 Agent 监听
|
||||
|
||||
当前入口:
|
||||
|
||||
```go
|
||||
listenv := flag.String("listen", envOr("FONU_AGENT_LISTEN", ":7700"), ...)
|
||||
```
|
||||
|
||||
`internal/agent.NewServer` 空配置时同样回落到:
|
||||
|
||||
```go
|
||||
cfg.ListenAddr = ":7700"
|
||||
```
|
||||
|
||||
`:7700` 等价于监听所有 IPv4 / IPv6 网卡。
|
||||
|
||||
### 2.2 传输安全
|
||||
|
||||
当前 Agent 使用明文 HTTP:
|
||||
|
||||
- Bearer Token 在网络上直接传输;
|
||||
- Token 已采用常量时间比较;
|
||||
- Agent 默认没有 TLS;
|
||||
- 安装脚本打印:
|
||||
|
||||
```text
|
||||
API: http://<VPS-IP>:7700
|
||||
```
|
||||
|
||||
### 2.3 中央 Fonu 连接
|
||||
|
||||
安装完成后,`AgentInstall` 写入:
|
||||
|
||||
```go
|
||||
AgentURL = fmt.Sprintf("http://%s:%d", server.SSHHost, 7700)
|
||||
```
|
||||
|
||||
中央 Fonu 后续直接访问 VPS 公网 IP 的 7700 端口。
|
||||
|
||||
### 2.4 当前问题
|
||||
|
||||
- 用户需要额外放行或确认 7700;
|
||||
- 如果防火墙忘记放行,Agent 显示不可达;
|
||||
- 如果放行,Token 暴露在明文网络中;
|
||||
- 部署工具和容器环境可能改变监听行为;
|
||||
- “默认安全”没有形成产品行为;
|
||||
- 安全策略主要依赖用户理解和手工操作。
|
||||
|
||||
---
|
||||
|
||||
## 三、设计目标
|
||||
|
||||
### 3.1 必须实现
|
||||
|
||||
1. 新安装默认不监听公网网卡。
|
||||
2. 安装过程自动建立中央 Fonu 到 Agent 的安全连接。
|
||||
3. 不需要用户手工配置网络或证书。
|
||||
4. Agent 升级时可自动迁移旧监听配置。
|
||||
5. 旧部署仍可显式使用公网 HTTP。
|
||||
6. 传输失败时给出可执行的诊断信息。
|
||||
7. 中央 Fonu 重启后可自动恢复连接。
|
||||
8. Agent 与中央 Fonu 的版本兼容策略保持清晰。
|
||||
|
||||
### 3.2 非目标
|
||||
|
||||
- 不尝试自动修改云厂商安全组;
|
||||
- 不要求用户申请域名或公网 CA 证书;
|
||||
- 不引入多租户权限模型;
|
||||
- 不把 Agent 管理 API 暴露给家庭用户的普通浏览器;
|
||||
- 不提供一个“自动回退到明文 HTTP”的危险路径。
|
||||
|
||||
---
|
||||
|
||||
## 四、方案对比
|
||||
|
||||
### 4.1 方案 A:公网 HTTP + Bearer Token(现状)
|
||||
|
||||
| 项目 | 评价 |
|
||||
| --- | --- |
|
||||
| 自动化 | 高 |
|
||||
| 安全性 | 低 |
|
||||
| 防火墙 | 需要放行 7700 |
|
||||
| 证书 | 不需要 |
|
||||
| 复杂度 | 低 |
|
||||
| 主要风险 | Token 明文、端口暴露、被动扫描 |
|
||||
|
||||
结论:只保留为显式兼容模式,不再作为默认。
|
||||
|
||||
### 4.2 方案 B:SSH 隧道 + Agent 回环监听(推荐默认)
|
||||
|
||||
| 项目 | 评价 |
|
||||
| --- | --- |
|
||||
| 自动化 | 很高 |
|
||||
| 安全性 | 高 |
|
||||
| 防火墙 | 不需要新增端口 |
|
||||
| 证书 | 不需要 |
|
||||
| 复杂度 | 中高,需要隧道生命周期管理 |
|
||||
| 依赖 | SSH 可达;本功能安装 Agent 时已经要求 SSH |
|
||||
| 主要优势 | 不暴露端口、不依赖域名和证书 |
|
||||
|
||||
结论:作为默认模式。
|
||||
|
||||
### 4.3 方案 C:Nginx HTTPS + 自签名证书固定
|
||||
|
||||
| 项目 | 评价 |
|
||||
| --- | --- |
|
||||
| 自动化 | 高 |
|
||||
| 安全性 | 高 |
|
||||
| 防火墙 | 需要放行一个 HTTPS 端口 |
|
||||
| 证书 | 自动生成和固定,不需要公网 CA |
|
||||
| 复杂度 | 中 |
|
||||
| 主要优势 | 中央 Fonu 可直接连接,不依赖常驻 SSH |
|
||||
| 主要限制 | 云安全组仍需用户放行端口 |
|
||||
|
||||
结论:作为可选直连模式。
|
||||
|
||||
### 4.4 方案 D:公网域名 + ACME 证书
|
||||
|
||||
| 项目 | 评价 |
|
||||
| --- | --- |
|
||||
| 自动化 | 中 |
|
||||
| 安全性 | 高 |
|
||||
| 防火墙 | 需要 443 或 DNS-01 |
|
||||
| 证书 | 需要域名、DNS 与 CA |
|
||||
| 复杂度 | 高 |
|
||||
| 用户成本 | 高 |
|
||||
|
||||
结论:不作为默认。可作为未来面向高级用户的能力。
|
||||
|
||||
---
|
||||
|
||||
## 五、推荐架构
|
||||
|
||||
### 5.1 默认数据流
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Web[Fonu Web] --> API[Fonu 后端]
|
||||
API --> Tunnel[SSH 隧道管理器]
|
||||
Tunnel -->|127.0.0.1:自动分配端口| SSH[SSH 加密连接]
|
||||
SSH --> VPSLoopback[VPS 127.0.0.1:7700]
|
||||
VPSLoopback --> Agent[fonu-agent]
|
||||
```
|
||||
|
||||
### 5.2 角色职责
|
||||
|
||||
| 组件 | 职责 |
|
||||
| --- | --- |
|
||||
| Fonu 后端 | 决定 transport、启动隧道、调用 AgentClient |
|
||||
| 隧道管理器 | 建立 SSH 本地转发、保持连接、重连、健康检查 |
|
||||
| fonu-agent | 默认只监听回环,不再负责公网暴露 |
|
||||
| 安装脚本 | 写入 `FONU_AGENT_LISTEN=127.0.0.1:7700`,禁止默认可公开 |
|
||||
| UI | 显示安全模式、连接状态、可选迁移和显式旧模式警告 |
|
||||
|
||||
### 5.3 连接抽象
|
||||
|
||||
中央 Fonu 不再把“公网 IP + 7700”当作 Agent 的唯一定义。新增 transport 概念:
|
||||
|
||||
```text
|
||||
tunnel SSH 本地转发,默认
|
||||
https-pin Nginx HTTPS + 证书指纹固定,可选
|
||||
http 公网明文,仅显式兼容
|
||||
```
|
||||
|
||||
`AgentClient` 仍使用普通 HTTP 客户端接口,但 baseURL 由 transport 管理:
|
||||
|
||||
- tunnel:`http://127.0.0.1:<localPort>`
|
||||
- https-pin:`https://<host>:<port>`
|
||||
- http:`http://<host>:7700`
|
||||
|
||||
---
|
||||
|
||||
## 六、默认模式:SSH 隧道
|
||||
|
||||
### 6.1 为什么默认走 SSH
|
||||
|
||||
安装 Agent 已经必须使用 SSH,因此:
|
||||
|
||||
- 不新增用户操作;
|
||||
- 不需要公网开放 7700;
|
||||
- 不需要证书和域名;
|
||||
- 不依赖云安全组修改;
|
||||
- SSH 主机密钥已经使用 TOFU 校验;
|
||||
- Token 继续保留,形成双层认证。
|
||||
|
||||
### 6.2 本地端口分配
|
||||
|
||||
每个 VPS 服务端分配一个稳定的本地回环端口:
|
||||
|
||||
```text
|
||||
127.0.0.1:<agent_local_port>
|
||||
```
|
||||
|
||||
分配方式建议:
|
||||
|
||||
1. 首次安装时在 `frp_servers.agent_local_port` 中保存;
|
||||
2. 可在 `17700-18700` 范围内分配;
|
||||
3. 分配时检查:
|
||||
- 未被其他服务端占用;
|
||||
- 未被本机其他 SSH 隧道占用;
|
||||
- 可以正常绑定。
|
||||
4. 保存后不再变化,便于重启恢复。
|
||||
|
||||
### 6.3 隧道管理器
|
||||
|
||||
新增:
|
||||
|
||||
```text
|
||||
internal/frp/agent_tunnel.go
|
||||
```
|
||||
|
||||
核心能力:
|
||||
|
||||
- `Ensure(serverID)`:确保隧道已启动;
|
||||
- `Stop(serverID)`:停止隧道;
|
||||
- `Restart(serverID)`:重建;
|
||||
- `State(serverID)`:返回 connected / reconnecting / failed;
|
||||
- 应用退出时统一关闭。
|
||||
|
||||
实现建议:
|
||||
|
||||
- 使用现有 `golang.org/x/crypto/ssh`;
|
||||
- 复用 `SSHInstaller` 的 known_hosts 校验;
|
||||
- SSH 连接使用 keepalive;
|
||||
- 本地监听使用 `127.0.0.1`,不绑定 `0.0.0.0`;
|
||||
- 连接断开后指数退避重连;
|
||||
- 每个服务端最多一个隧道实例;
|
||||
- 同一 `AgentClient` 复用 HTTP 连接。
|
||||
|
||||
### 6.4 健康检查
|
||||
|
||||
隧道建立后执行:
|
||||
|
||||
1. 本地端口可以连接;
|
||||
2. `GET /api/v1/ping` 返回 200;
|
||||
3. Bearer Token 验证通过;
|
||||
4. `GET /api/v1/status` 返回 Agent 版本。
|
||||
|
||||
只有四项都通过,才把 transport 标记为 connected。
|
||||
|
||||
### 6.5 连接状态
|
||||
|
||||
前端需要显示:
|
||||
|
||||
```text
|
||||
传输方式:SSH 隧道
|
||||
本地端口:127.0.0.1:177xx
|
||||
Agent 地址:127.0.0.1:7700(VPS 回环)
|
||||
隧道状态:已连接 / 重连中 / 失败
|
||||
最后错误
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、Agent 默认监听与防误开
|
||||
|
||||
### 7.1 默认值
|
||||
|
||||
修改:
|
||||
|
||||
```go
|
||||
const defaultListenAddr = "127.0.0.1:7700"
|
||||
```
|
||||
|
||||
以下位置同步:
|
||||
|
||||
- `cmd/fonu-agent/main.go`
|
||||
- `internal/agent.NewServer`
|
||||
- `scripts/agent-install.sh`
|
||||
- `internal/frp/agent_installer.go` 内嵌安装脚本
|
||||
|
||||
### 7.2 远程监听保护
|
||||
|
||||
如果监听地址不是回环:
|
||||
|
||||
```text
|
||||
0.0.0.0:7700
|
||||
:7700
|
||||
[::]:7700
|
||||
VPS公网IP:7700
|
||||
```
|
||||
|
||||
则必须显式设置:
|
||||
|
||||
```dotenv
|
||||
FONU_AGENT_ALLOW_REMOTE=1
|
||||
```
|
||||
|
||||
否则 Agent 拒绝启动并输出:
|
||||
|
||||
```text
|
||||
检测到 Agent 将监听非回环地址,但未显式允许远程访问。
|
||||
默认安全模式只监听 127.0.0.1:7700。
|
||||
如确认需要公网明文访问,请设置 FONU_AGENT_ALLOW_REMOTE=1。
|
||||
```
|
||||
|
||||
### 7.3 旧配置迁移
|
||||
|
||||
旧版本 `agent.env` 可能没有 `FONU_AGENT_LISTEN`,此时:
|
||||
|
||||
1. 新 Agent 默认监听回环;
|
||||
2. 安装脚本显式写入:
|
||||
|
||||
```dotenv
|
||||
FONU_AGENT_LISTEN=127.0.0.1:7700
|
||||
```
|
||||
|
||||
3. 中央 Fonu 在执行「升级 Agent」时同步建立隧道;
|
||||
4. 升级完成后切换 transport;
|
||||
5. 旧公网地址从 `agent_url` 中移除;
|
||||
6. 不停留手工维护窗口。
|
||||
|
||||
### 7.4 状态接口
|
||||
|
||||
Agent `/api/v1/status` 新增:
|
||||
|
||||
```json
|
||||
{
|
||||
"listen_addr": "127.0.0.1:7700",
|
||||
"listen_scope": "loopback",
|
||||
"remote_access_enabled": false,
|
||||
"transport_security": "loopback"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、自动安装流程
|
||||
|
||||
### 8.1 新安装
|
||||
|
||||
1. 用户填写 VPS SSH 信息。
|
||||
2. 中央 Fonu 通过 SSH 探测系统与 Nginx。
|
||||
3. 分配 `agent_local_port`。
|
||||
4. 上传 Agent 二进制。
|
||||
5. 安装脚本写入:
|
||||
- Token;
|
||||
- `FONU_AGENT_LISTEN=127.0.0.1:7700`;
|
||||
- systemd 服务。
|
||||
6. 启动 Agent。
|
||||
7. 通过 SSH 本地转发建立隧道。
|
||||
8. 调用:
|
||||
- `GET /api/v1/ping`
|
||||
- `GET /api/v1/status`
|
||||
9. 保存:
|
||||
- token 密文;
|
||||
- transport=`tunnel`;
|
||||
- local port;
|
||||
- AgentVersion。
|
||||
10. UI 显示“安全模式已启用”。
|
||||
|
||||
### 8.2 自动迁移旧安装
|
||||
|
||||
1. 检测现有 `agent_url` 是否为 `http://公网IP:7700`。
|
||||
2. 显示“可升级到安全模式”,但不强制立即迁移。
|
||||
3. 用户点击「升级 Agent」后:
|
||||
- 安装新二进制;
|
||||
- 重写 `agent.env` 为回环监听;
|
||||
- 重启服务;
|
||||
- 建立隧道;
|
||||
- 验证连通;
|
||||
- 切换 central transport。
|
||||
4. 只有隧道验证成功后,才关闭旧公网连接。
|
||||
5. 失败时保留旧 Agent 配置和旧连接,自动回滚。
|
||||
|
||||
### 8.3 应用重启恢复
|
||||
|
||||
1. 读取启用管理且 transport=tunnel 的服务端。
|
||||
2. 逐个调用 `Tunnel.Ensure`。
|
||||
3. 启动失败不阻塞整个 Fonu 启动。
|
||||
4. UI 显示重连状态。
|
||||
5. 后台按指数退避继续重试。
|
||||
|
||||
---
|
||||
|
||||
## 九、可选模式:HTTPS + 证书固定
|
||||
|
||||
### 9.1 适用场景
|
||||
|
||||
- 不希望长期维护 SSH 隧道;
|
||||
- 可以接受开放一个 HTTPS 端口;
|
||||
- 没有域名或不想申请公网证书;
|
||||
- 希望 Agent API 可被中央 Fonu直接访问。
|
||||
|
||||
### 9.2 安装后切换流程
|
||||
|
||||
首次安装默认仍使用 SSH 隧道。只有用户在「公网 Agent」页明确切换到 HTTPS 直连时,才执行以下步骤:
|
||||
|
||||
1. Agent 仍监听 `127.0.0.1:7700`。
|
||||
2. 切换流程生成自签名证书:
|
||||
|
||||
```text
|
||||
/etc/fonu-agent/tls/agent.crt
|
||||
/etc/fonu-agent/tls/agent.key
|
||||
```
|
||||
|
||||
3. 自动寻找可用端口:
|
||||
- 优先 7443;
|
||||
- 其次 8443、9443;
|
||||
- 若 443 空闲且未占用可提供选项,但不默认抢占。
|
||||
4. 生成独立 Nginx server block:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 7443 ssl;
|
||||
ssl_certificate /etc/fonu-agent/tls/agent.crt;
|
||||
ssl_certificate_key /etc/fonu-agent/tls/agent.key;
|
||||
|
||||
location /api/v1/ {
|
||||
proxy_pass http://127.0.0.1:7700;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
5. 返回证书 SHA-256 指纹。
|
||||
6. 中央 Fonu 保存 pin,并使用自定义校验。
|
||||
|
||||
### 9.3 TLS 固定
|
||||
|
||||
不能使用:
|
||||
|
||||
```go
|
||||
InsecureSkipVerify: true
|
||||
```
|
||||
|
||||
应实现:
|
||||
|
||||
```go
|
||||
VerifyPeerCertificate(rawCerts [][]byte, _ [][]*x509.Certificate) error {
|
||||
// 计算证书 DER 的 SHA-256
|
||||
// 与数据库中保存的 pin 做常量时间比较
|
||||
// 同时校验有效期与 SAN(如可校验)
|
||||
}
|
||||
```
|
||||
|
||||
首次安装必须通过 SSH 获取指纹,避免首次连接被中间人截获。
|
||||
|
||||
### 9.4 防火墙
|
||||
|
||||
首版不自动修改主机防火墙。阶段 4 之后,在用户明确确认时可以辅助生成并执行主机防火墙命令:
|
||||
|
||||
- ufw;
|
||||
- firewalld;
|
||||
- nftables / iptables。
|
||||
|
||||
云厂商安全组始终不能自动修改。UI 必须提示:
|
||||
|
||||
```text
|
||||
请在云控制台放行 TCP 7443。主机防火墙需要你确认后由 Fonu 执行,Fonu 不会修改云安全组。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、兼容模式:显式公网 HTTP
|
||||
|
||||
仅用于旧部署迁移或用户明确要求:
|
||||
|
||||
```dotenv
|
||||
FONU_AGENT_LISTEN=:7700
|
||||
FONU_AGENT_ALLOW_REMOTE=1
|
||||
```
|
||||
|
||||
中央 Fonu UI 必须:
|
||||
|
||||
- 显示“公网明文传输”红色状态;
|
||||
- 不在新安装中默认选择;
|
||||
- 不支持由自动模式静默回退;
|
||||
- 显示迁移到 SSH 隧道或 HTTPS 的按钮;
|
||||
- 在变更时记录审计事件。
|
||||
|
||||
旧 transport 允许读取和继续连接,但所有新增安装默认使用 tunnel。
|
||||
|
||||
---
|
||||
|
||||
## 十一、数据模型变更
|
||||
|
||||
建议新增迁移:
|
||||
|
||||
```sql
|
||||
ALTER TABLE frp_servers ADD COLUMN agent_transport TEXT NOT NULL DEFAULT 'http';
|
||||
ALTER TABLE frp_servers ADD COLUMN agent_local_port INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE frp_servers ADD COLUMN agent_tls_pin TEXT NOT NULL DEFAULT '';
|
||||
ALTER TABLE frp_servers ADD COLUMN agent_listen_addr TEXT NOT NULL DEFAULT '';
|
||||
ALTER TABLE frp_servers ADD COLUMN agent_transport_state TEXT NOT NULL DEFAULT 'unknown';
|
||||
ALTER TABLE frp_servers ADD COLUMN agent_transport_error TEXT NOT NULL DEFAULT '';
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| `agent_transport` | `tunnel` / `https-pin` / `http` |
|
||||
| `agent_local_port` | 隧道本地回环端口 |
|
||||
| `agent_tls_pin` | HTTPS 证书 DER SHA-256 |
|
||||
| `agent_listen_addr` | Agent 实际监听地址缓存 |
|
||||
| `agent_transport_state` | `connected` / `reconnecting` / `failed` / `unknown` |
|
||||
| `agent_transport_error` | 最近一次连接错误 |
|
||||
|
||||
### 11.1 兼容迁移
|
||||
|
||||
旧数据:
|
||||
|
||||
```text
|
||||
agent_transport = http
|
||||
```
|
||||
|
||||
新安装:
|
||||
|
||||
```text
|
||||
agent_transport = tunnel
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十二、API 与前端变更
|
||||
|
||||
### 12.1 API
|
||||
|
||||
`FrpServer` JSON 增加:
|
||||
|
||||
```json
|
||||
{
|
||||
"agent_transport": "tunnel",
|
||||
"agent_transport_state": "connected",
|
||||
"agent_local_port": 17701,
|
||||
"agent_listen_addr": "127.0.0.1:7700",
|
||||
"agent_transport_error": ""
|
||||
}
|
||||
```
|
||||
|
||||
新增管理端点:
|
||||
|
||||
| 方法 | 路径 | 作用 |
|
||||
| --- | --- | --- |
|
||||
| POST | `/api/frpmulti/servers/{id}/agent/transport` | 切换 tunnel / https-pin / http |
|
||||
| POST | `/api/frpmulti/servers/{id}/agent/tunnel/restart` | 重启隧道 |
|
||||
| GET | `/api/frpmulti/servers/{id}/agent/transport` | 读取详细状态 |
|
||||
|
||||
### 12.2 前端
|
||||
|
||||
「公网 Agent」页新增传输模式卡:
|
||||
|
||||
- SSH 隧道,默认;
|
||||
- HTTPS + 证书固定,可选;
|
||||
- 公网 HTTP 明文,兼容。
|
||||
|
||||
显示:
|
||||
|
||||
```text
|
||||
传输方式:SSH 隧道
|
||||
隧道状态:已连接
|
||||
本地入口:127.0.0.1:17701
|
||||
Agent 监听:127.0.0.1:7700
|
||||
安全等级:安全
|
||||
```
|
||||
|
||||
旧模式显示:
|
||||
|
||||
```text
|
||||
公网明文 HTTP
|
||||
风险:Token 会通过网络明文传输
|
||||
建议迁移到 SSH 隧道
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十三、自动回滚
|
||||
|
||||
迁移或切换 transport 失败时:
|
||||
|
||||
1. 保留旧 transport 与旧 Agent 配置;
|
||||
2. 不覆盖旧 Token;
|
||||
3. 不删除旧公网端口配置;
|
||||
4. 如果已经重写 `agent.env`,恢复旧文件;
|
||||
5. 如果 Agent 已重启但新连接失败,重新启动旧服务;
|
||||
6. 向 UI 返回完整错误和回滚结果。
|
||||
|
||||
任何自动迁移都必须满足:
|
||||
|
||||
```text
|
||||
新连接验证成功
|
||||
→ 才提交数据库 transport
|
||||
→ 才停止旧监听
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十四、测试计划
|
||||
|
||||
### 14.1 单元测试
|
||||
|
||||
- 默认监听地址是回环;
|
||||
- 非回环监听缺少 `FONU_AGENT_ALLOW_REMOTE` 时拒绝启动;
|
||||
- 回环监听无需额外变量;
|
||||
- `agent_transport` 序列化与旧数据兼容;
|
||||
- 隧道本地端口分配、冲突与释放;
|
||||
- 隧道重连、退避和关闭;
|
||||
- 证书 pin 正确、证书变化、pin 不匹配时拒绝;
|
||||
- 旧 HTTP transport 继续可用并产生警告。
|
||||
|
||||
### 14.2 集成测试
|
||||
|
||||
- 在测试 SSH 服务上建立本地转发;
|
||||
- Agent 只监听 127.0.0.1;
|
||||
- 应用重启后隧道自动恢复;
|
||||
- SSH 断开后重连;
|
||||
- 多服务端并发隧道;
|
||||
- 迁移前失败回滚;
|
||||
- 迁移成功后旧公网端口关闭。
|
||||
|
||||
### 14.3 真机验证
|
||||
|
||||
至少覆盖:
|
||||
|
||||
- Debian / Ubuntu / CentOS;
|
||||
- fnOS 中的 Fonu;
|
||||
- 宝塔 Nginx;
|
||||
- 已存在 80 / 443 / 7443 占用的 VPS;
|
||||
- 云安全组只开放 SSH 的 VPS;
|
||||
- 云安全组开放 7443 的可选 HTTPS 模式。
|
||||
|
||||
### 14.4 验收条件
|
||||
|
||||
- 新安装后 `ss -tlnp` 只能看到 Agent 监听 `127.0.0.1:7700`;
|
||||
- 公网扫描不到 7700;
|
||||
- 无需新增云安全组规则;
|
||||
- UI 显示隧道已连接;
|
||||
- Fonu 重启后自动恢复;
|
||||
- 「升级 Agent」可以自动迁移旧配置;
|
||||
- 失败时不会丢失旧连接。
|
||||
|
||||
---
|
||||
|
||||
## 十五、实施阶段
|
||||
|
||||
### 阶段 1:默认回环与防误开
|
||||
|
||||
- Agent 默认监听改为 `127.0.0.1:7700`;
|
||||
- 非回环监听要求 `FONU_AGENT_ALLOW_REMOTE=1`;
|
||||
- 安装脚本显式写入监听地址;
|
||||
- UI 显示监听范围。
|
||||
|
||||
该阶段暂不自动切换中央连接,避免破坏旧部署。
|
||||
|
||||
### 阶段 2:SSH 隧道管理器
|
||||
|
||||
- 新增数据库字段;
|
||||
- 新增隧道管理器和 AgentClient transport;
|
||||
- 安装后自动建立隧道;
|
||||
- 应用重启恢复;
|
||||
- UI 显示 transport 状态。
|
||||
|
||||
### 阶段 3:自动迁移旧 Agent
|
||||
|
||||
- 检测旧公网 HTTP;
|
||||
- 「升级 Agent」时执行安全迁移;
|
||||
- 成功切换后关闭旧入口;
|
||||
- 失败自动回滚。
|
||||
|
||||
### 阶段 4:可选 HTTPS + pin
|
||||
|
||||
- 自动生成证书;
|
||||
- Nginx server block;
|
||||
- TLS pin;
|
||||
- 防火墙辅助;
|
||||
- UI 可选切换。
|
||||
|
||||
### 阶段 5:收紧默认
|
||||
|
||||
- 新安装不再接受公网 HTTP;
|
||||
- 兼容模式需要明确的高风险确认;
|
||||
- 文档和通知引导迁移。
|
||||
|
||||
---
|
||||
|
||||
## 十六、决策结论
|
||||
|
||||
以下决策已于 2026-09-28 确定,后续实施按此执行。
|
||||
|
||||
| 编号 | 决策 | 执行设定 | 理由 |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | SSH 隧道作为唯一默认模式 | 首次安装不提供模式选择,统一安装为回环监听 + SSH 隧道;HTTPS 直连只作为安装后的高级切换项 | 现有安装流程已经依赖 SSH;默认路径必须最少输入、最少网络要求 |
|
||||
| 2 | 隧道本地端口使用固定范围 | 固定为 `17700-18700`,绑定 `127.0.0.1`;分配结果持久化;启动时先复用持久化端口,再在范围内顺序查找空闲端口;范围耗尽时明确报错,不使用临时端口 | 固定范围便于排查和审计;持久化避免每次重启变化;不回退临时端口避免地址漂移 |
|
||||
| 3 | 隧道跟随主应用生命周期 | 使用应用内 `agent_tunnel` 管理器,在 Fonu 启动后按服务端恢复;应用退出时统一关闭;断线后指数退避重连;首版不新增独立 systemd 服务 | 当前项目是单进程控制面,调度器、FRP、监控均在同一生命周期内,新增守护进程会扩大部署复杂度 |
|
||||
| 4 | 公网 HTTP 保留整个 1.x 兼容期 | 自 `1.4.0` 起不再允许新安装选择 HTTP;存量连接继续可用但显示高危警告并提供迁移;计划在 `2.0.0` 移除 | 需要给旧 Agent 和环境留出迁移窗口,同时从版本边界上明确技术债的截止点 |
|
||||
| 5 | HTTPS 自签名证书使用短期自动轮换 | ECDSA P-256,有效期 365 天;剩余 30 天时自动轮换;轮换期间同时接受旧 pin 和新 pin,双 pin 窗口 7 天;优先通过现有 SSH 通道获取新指纹后再切换 | 避免长期证书失管;双 pin 防止轮换瞬间把所有中央连接锁死 |
|
||||
| 6 | 首版不自动改主机防火墙 | 首先只检测、展示和提示;SSH 隧道模式本身不需要放行新端口;HTTPS 高级模式后续再提供显式的“一键放行主机防火墙”操作,并始终不修改云厂商安全组 | 防火墙和云安全组属于高风险外部状态;首版先把安全默认值落地,避免自动变更导致 SSH 或现有服务失联 |
|
||||
|
||||
### 16.1 决策对实施阶段的影响
|
||||
|
||||
- 阶段 1 只做 Agent 默认回环和防误开。
|
||||
- 阶段 2 实现 `17700-18700` 的持久化端口分配与应用内隧道管理器。
|
||||
- 阶段 3 完成旧 Agent 自动迁移;迁移失败必须回到旧 transport。
|
||||
- 阶段 4 增加 HTTPS + pin 的高级模式、证书轮换和双 pin 窗口。
|
||||
- `1.4.0` 起前端不再允许新建 HTTP transport。
|
||||
- `2.0.0` 删除 `http` transport 和旧 Agent 兼容分支。
|
||||
- 防火墙变更仅在阶段 4 之后按用户明确操作执行,首版不实现自动写规则。
|
||||
|
||||
---
|
||||
|
||||
## 十七、最终建议
|
||||
|
||||
优先实现前三个阶段:
|
||||
|
||||
1. Agent 默认回环;
|
||||
2. SSH 隧道自动建立与恢复;
|
||||
3. 旧 Agent 自动迁移并支持回滚。
|
||||
|
||||
这三步完成后,默认部署不再暴露公网 7700,也不需要用户修改 Composer 或防火墙。HTTPS + pin 与防火墙辅助放在后续阶段,作为需要直连用户的可选增强。这样可以在不扩大用户操作成本的前提下,完成 P0-5 的安全目标。
|
||||
@@ -458,6 +458,10 @@ func (s *Server) clearLimitState(domain string) error
|
||||
|
||||
## 3.5 P0-5:明确 Agent 默认监听策略
|
||||
|
||||
> 方案文档:`agent-listen-strategy-plan.md`(2026-09-28,待实施)
|
||||
|
||||
> 实施状态:阶段 1-3 已随 v1.4.0 实施(默认回环、SSH 隧道、旧 HTTP 自动迁移);HTTPS + pin 高级模式待后续。
|
||||
|
||||
### 3.5.1 现状
|
||||
|
||||
- `cmd/fonu-agent/main.go` 默认 `:7700`。
|
||||
|
||||
@@ -238,16 +238,16 @@ FONU_VERSION=<旧版本> docker compose up -d --no-deps --force-recreate fonu
|
||||
|
||||
## 10. 在线升级验证
|
||||
|
||||
示例页面用于验证升级结果。v1.3.9 的验证流程:
|
||||
示例页面用于验证升级结果。v1.4.0 的验证流程:
|
||||
|
||||
1. 确认当前线上实例为 v1.3.0,且 `fonu-updater` sidecar 已运行。
|
||||
2. 确认远端 `main` 分支的 `VERSION` 为 `1.3.9`。
|
||||
2. 确认远端 `main` 分支的 `VERSION` 为 `1.4.0`。
|
||||
3. 在侧栏看到「一键升级」后点击并确认。
|
||||
4. 等待升级弹窗显示成功,页面自动刷新。
|
||||
5. 打开侧栏「示例页面」,确认:
|
||||
- 页面路由为 `/example`;
|
||||
- 页面显示的版本为 `1.3.9`;
|
||||
- 页面显示验证标识 `v1.3.9-example-page`;
|
||||
- 页面显示的版本为 `1.4.0`;
|
||||
- 页面显示验证标识 `v1.4.0-example-page`;
|
||||
- 页面显示独立的「本次升级验证」区块;
|
||||
- 「升级验证」显示为「通过」。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user