Files
Havline/docs/frps管理方案.md
T

157 lines
11 KiB
Markdown
Raw Permalink Normal View History

2026-09-23 09:40:59 +08:00
# FRPS 服务端自动管理方案(frps-manager)
2026-10-01 16:54:35 +08:00
> 目标:frpc 端在 Havline 提交穿透规则后,frps 端**自动完成反向代理配置与生效**,实现域名无端口访问(`http://tv.36800.cc`),并自动管理 VPS 侧证书。本文是基于现有项目(Havline v1.1.0 FRP 多服务端模块)的实施方案,不引入新服务、不改 frp 二进制。
2026-09-23 09:40:59 +08:00
## 1. 现状与问题
当前(v1.1.0)frpc 侧规则提交后:
| 环节 | 现状 | 问题 |
| --- | --- | --- |
| tcp 规则注册(远程端口) | ✅ 自动(frpc 登录时向 frps 动态注册) | 无 |
| http 规则域名路由 | ⚠️ 需 frps.toml 预先配置 `vhostHTTPPort` | 首次使用 http 类型时 VPS 要手工改配置+重启 |
2026-10-01 16:54:35 +08:00
| frps.toml 生成 | ✅ Havline 一键生成,用户手动复制到 VPS | 每次变更都要 SSH 手工同步 |
2026-09-23 09:40:59 +08:00
| VPS 端口释放(80/443 被占) | ❌ 手动 SSH 停 Nginx | `port unavailable` 最常见根因 |
| 改配置后生效 | ❌ 手动 `pkill frps` 重启(frp 无热加载) | 容易忘、容易误 |
| VPS 侧证书 | ❌ 无 | HTTPS 要在 VPS 手工装证书 |
2026-10-01 16:54:35 +08:00
| 配置漂移检测 | ❌ 无 | VPS 上的文件与 Havline 数据库可能不一致 |
2026-09-23 09:40:59 +08:00
## 2. 总体设计
2026-10-01 16:54:35 +08:00
在 Havline(frpc 所在机器)新增 **frps-manager** 子系统:Havline 通过 **SSH** 连接 VPS,执行「检测 → 生成 → 推送 → 生效 → 验证」闭环。VPS 侧**零安装**(只要求 frps + SSH)。
2026-09-23 09:40:59 +08:00
```text
2026-10-01 16:54:35 +08:00
Havline (NAS) VPS (38.95.74.87)
2026-09-23 09:40:59 +08:00
┌─────────────────────────────┐ ┌──────────────────────────┐
│ FRP 模块(现有) │ │ frps (7000/80/443/7500) │
│ 规则/服务端 CRUD │ │ ↑ frpc 动态注册端口 │
│ frps-manager(新增) │ SSH │ frps.toml (推送产物) │
2026-10-01 16:54:35 +08:00
│ 检测→生成→推送→reload→验证 │ ────────→ │ /etc/havline/frps/ │
│ 证书申请→推送→挂载 │ │ /etc/havline/frps/certs/ │
2026-09-23 09:40:59 +08:00
└─────────────────────────────┘ └──────────────────────────┘
```
2026-10-01 16:54:35 +08:00
核心思路:**frps 不认识"反代",它只认 frps.toml**。因此"自动反代"= ① 规则变化时重算出应然的 frps.toml(含 vhost 端口、subDomainHost、TLS 配置)→ ② 与 VPS 现状 diff → ③ 无变化则跳过,有变化则原子推送 → ④ 通过 frps **admin API 热重载**(无需重启进程)→ ⑤ 回读验证。证书同理:Havline 证书页现有 ACME 能力签好后把证书文件推到 VPS 并写入 frps.toml 的 `transport.tls`/`webServer.tls` 段。
2026-09-23 09:40:59 +08:00
## 3. 服务端模型扩展(frp_servers 表)
新增「服务端连接信息」(加密存储,复用 secret.Box):
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `ssh_host` | TEXT | VPS SSH 地址(可与 server_addr 不同) |
| `ssh_port` | INTEGER | 默认 22 |
| `ssh_user` | TEXT | 建议 root 或具备 sudo 的用户 |
| `ssh_auth` | TEXT | `password` / `key` |
| `ssh_secret_enc` | TEXT | 密码或私钥(加密) |
2026-10-01 16:54:35 +08:00
| `frps_dir` | TEXT | VPS 上 frps 目录,默认 `/etc/havline/frps` |
2026-09-23 09:40:59 +08:00
| `frps_bin` | TEXT | frps 二进制路径,默认 `/usr/local/bin/frps` |
| `mgmt_enabled` | INTEGER | 是否启用自动管理(0/1,默认 0=纯手动,向后兼容) |
迁移 `023_frp_server_ssh.sql`。SSH 凭据用 secret.Box 加密,接口不回显(同 Token 处理)。
## 4. 核心流程
### 4.1 检测(Probe)——服务端详情新增「检测服务端」按钮
一次 SSH 会话内批量执行(只读,不改任何东西):
```bash
frps --version # 版本
ss -tlnp | grep -E ':(80|443|7000) ' # 端口占用者(frps? nginx? 其他?)
systemctl is-active nginx frps # 服务状态
cat /proc/$(pidof frps)/cmdline # 实际使用的配置路径
cat <配置路径> # 现有 frps.toml 内容(做 diff)
```
2026-10-01 16:54:35 +08:00
返回结构化报告:frps 版本/运行状态/配置路径、80/443 占用者判定(frps/nginx/其他/空闲)、现有 frps.toml 与 Havline 期望配置的 **diff 摘要**、待办建议(如「80 被 nginx 占用,需释放」)。这就是用户之前反复手工排查的自动化。
2026-09-23 09:40:59 +08:00
### 4.2 下发(Apply)——「自动反代」的主流程
触发时机:用户点「下发配置」,或规则保存后若 `mgmt_enabled` 且检测到配置将变化(规则含 http 类型 / 证书变更)自动触发。
1. **生成期望配置**:扩展现有 `buildFRPSServerConfig`:
- 存在 http/https/tcpmux 规则 → 输出 `vhostHTTPPort = 80`、`vhostHTTPSPort = 443`(去端口访问的关键);
- 存在 subdomain 规则 → 输出 `subDomainHost = <用户在服务端表单新填的主域>`;
- 证书启用时输出 `transport.tls.force` / `webServer.tls` 段;
2026-10-01 16:54:35 +08:00
2. **SSH 推送(原子)**:新内容写 `/etc/havline/frps/frps.toml.new` → `mv` 原子替换 → 旧文件留 `frps.toml.bak`(回滚点);
2026-09-23 09:40:59 +08:00
3. **热重载**:调 frps admin API `PUT /api/reload`(frps webServer 7500 已有 Basic Auth 凭据)——**不杀进程**,连接不断;API 不可用时降级 `systemctl restart frps`(nohup 场景提示用户);
4. **验证**:重读 VPS 上的 frps.toml 确认与期望一致 + `ss` 确认 80/443 已由 frps 监听 + 通过公网侧发起一次探测请求;
5. 全程动作与输出写入系统日志(复用 logstore),UI 弹窗展示每步结果。
### 4.3 释放端口(安全加固提示,不偷偷杀人)
检测发现 80/443 被 nginx 等占用时,**不自动杀进程**(危险动作),而是:
- 检测报告中标红 + 给出一键命令;
- UI 提供「释放端口」按钮:二次确认后执行 `systemctl stop nginx && systemctl disable nginx`(仅当占用者确认为 nginx 时可点,其他占用者只提示不动手);
- 释放后自动重跑 Apply 验证闭环。
### 4.4 证书管理(VPS 侧 HTTPS)
2026-10-01 16:54:35 +08:00
复用 Havline 证书页现有 ACME(lego)能力,证书签发在 NAS 侧完成(DNS-01,无需 VPS 参与),然后:
2026-09-23 09:40:59 +08:00
1. 证书页选「部署到 VPS」→ 选目标服务端;
2026-10-01 16:54:35 +08:00
2. SSH 推送 `fullchain.pem` / `privkey.pem` 到 `/etc/havline/frps/certs/<域名>/`(0600);
2026-09-23 09:40:59 +08:00
3. frps.toml 写入 `webServer.tls.certFile/keyFile`(管理面板 HTTPS);对外流量 TLS 若需要也在 frps 侧终止时,走 `transport.tls` 相关段(v0.71 支持 `transport.tls.force` + 证书);
2026-10-01 16:54:35 +08:00
4. 续期:Havline 证书定时任务续期成功后自动重推 + reload(证书 60 天滚动,VPS 侧无感)。
2026-09-23 09:40:59 +08:00
2026-10-01 16:54:35 +08:00
> 设计取舍:对外业务的 HTTPS 终止仍推荐在 **Havline Nginx(NAS 侧)**(本手册方案 A 架构),frps 侧证书用于 webServer 管理面板与 `tls.force` 场景。若用户想让 VPS 终止 TLS,同一套推送机制也覆盖。
2026-09-23 09:40:59 +08:00
## 5. API 与 UI
### 5.1 新增 API(挂在 `/api/frpmulti` 下,鉴权与现有中间件一致)
| 方法/路径 | 作用 |
| --- | --- |
| `PUT /servers/{id}/ssh` | 保存 SSH 连接信息(加密存储) |
| `GET /servers/{id}/probe` | 检测:frps 状态/端口占用/配置 diff |
| `POST /servers/{id}/apply` | 下发期望配置 + reload + 验证 |
| `POST /servers/{id}/release-port` | 释放被占端口(body: `{port, confirm: true}`) |
| `POST /servers/{id}/push-cert` | 推送证书到 VPS 并挂载 |
### 5.2 前端(FrpView.vue)
- 服务端表单「高级配置」折叠区新增「远程管理」分组:SSH 地址/端口/用户/认证方式/密钥(ConfiguredSecretField,v-model)/frps 目录;
- 服务端列表操作列新增「管理」按钮 → 弹窗(复用 `proxy-modal` 自绘骨架)三块:检测报告(分色状态行)、diff 视图(`<pre>` 左右对照期望/现状)、操作按钮(下发配置 / 释放端口 / 推送证书);
- 规则保存时的自动下发提示:非阻塞 toast「检测到 vhost 配置变化,点击下发」。
## 6. 实现拆解与工作量
| 模块 | 文件 | 内容 | 量级 |
| --- | --- | --- | --- |
| 迁移 | `migrations/023_frp_server_ssh.sql` | SSH 字段 | 小 |
| SSH 客户端 | `internal/frp/ssh.go`(新) | 连接池/单会话命令执行/SFTP 推送/超时 | 中(x/crypto/ssh 已在 go.mod) |
| 检测 | `internal/frp/probe.go`(新) | 探测命令编排 + 结果结构体 + 80 占用者判定 | 中 |
| 配置 diff/应用 | `internal/frp/frps_apply.go`(新) | 期望配置生成(扩展现有 frps_template)、diff、原子推送、admin API reload、验证 | 中 |
| 证书推送 | `internal/frp/cert_push.go`(新) | 证书文件推送 + frps.toml 证书段写入 | 小 |
| Service/API | `frpmulti_handler.go` + `router.go` | 5 个端点 | 小 |
| 前端 | `FrpView.vue` + `client.ts` | 管理弹窗 + 表单分组 + 按钮 | 中 |
| 测试 | `probe_test.go` `frps_apply_test.go` | 命令输出解析、diff、原子写逻辑 | 中 |
总计约 1500–2000 行(含测试),纯增量、不动现有链路(`mgmt_enabled=0` 时行为与 v1.1.0 完全一致)。
## 7. 安全设计
1. SSH 凭据 secret.Box 加密落库,API 永不回显(同 token 掩码机制);
2026-10-01 16:54:35 +08:00
2. 推荐文档引导用户用**密钥登录**(Havline 可一键生成 ed25519 密钥对、展示公钥让用户贴到 VPS `authorized_keys`);
3. 所有远程命令为**固定白名单模板**(版本/端口/状态/替换文件/reload),不拼接用户输入,杜绝命令注入;SFTP 只写 `/etc/havline/frps/` 前缀内路径;
2026-09-23 09:40:59 +08:00
4. 危险动作(释放端口、重启 frps)二次确认 + 动作日志;
5. Apply 幂等:重复执行无副作用(diff 无变化即跳过);
6. frps admin API 调用走本机 127.0.0.1:7500(SSH 远端执行 curl),不暴露公网。
## 8. 里程碑
| 阶段 | 内容 | 验收 |
| --- | --- | --- |
| M1 | 迁移 + SSH 客户端 + 检测(Probe) | 服务端「检测」按钮能报告 frps 状态与 80 占用者 |
| M2 | 期望配置生成 + diff + 原子推送 + reload + 验证 | 改规则后一键下发,`http://域名` 直达,`port unavailable` 类问题由系统自愈 |
| M3 | 证书推送 + 续期联动 | 证书页一键部署到 VPS,续期自动重推 |
| M4 | UI 完善 + 文档(手册第 6 节追加方案 A') | 手册更新,`port unavailable` 类问题由系统自愈 |
## 9. 明确不做(本期)
- 不实现 VPS 伴生 agent(能力更强但需安装,作为后续可选演进);
- 不做 frps 二进制的远程安装/升级(用户自装,检测报告给出版本即可);
- 不做多 VPS 并行下发编排(现有逐服务端模型已覆盖);
- 不改 frp 二进制、不依赖 frp 私有接口(只用 admin API 与文件系统)。