试想这样一个场景:我拥有多台服务器,但这些服务器均没有公网 IP 地址。为此,我租用了一些具备公网 IP 的服务器作为跳板,通过运行 Frp 将内网服务器代理至公网,从而构建起一个由多个节点组成的 FRP 网络。
然而,现有的 FRP 网络在实际运维中有一个明显痛点:每当我需要在这个网络中增加或删除设备,或是调整端口映射时,都必须登录对应的 frpc 节点,手动修改配置文件并重启 frpc 进程。这一过程不仅繁琐,而且在节点数量增多时显得效率低下。
鉴于内网服务器通常具备较高的性能,我们可以借鉴即时通讯系统的设计思想,构建一套统一的管理体系,通过一个监控进程来集中管理整个 FRP 网络,从而避免因网络结构变动而频繁在多台服务器间进行配置操作。
我将该项目命名为 UFM(Union of FRP Manager)。系统整体分为服务端与客户端两部分:
服务端(UFMS):提供 Web 管理界面,用于管理跳板机与内网服务器之间的端口映射关系。用户可通过该界面添加正在运行的 frps 或 UFMC 节点,动态调整 FRP 网络中的端口设置,并向客户端下达管理指令。
客户端(UFMC):运行于内网服务器中,接收来自 UFMS 的指令,控制本地的 frpc 进程,自动完成配置文件的修改与进程重启。每台内网服务器均运行一个 UFMC 进程,并通过 NAT 方式与云端的 UFMS 保持通信。这种方式既避免占用已映射的网络资源,也能在进程异常时保持连接稳定,提升系统整体鲁棒性。
为保证系统安全,每个 UFMS 在首次启动时会生成一个唯一的 UUID。UFMC 在连接时必须验证此 UUID 是否匹配,只有在一致时才允许接入。因此,UFMC 首次运行时需配置由 UFMS 提供的 UUID。此外,该 UUID 也将作为整个 FRP 网络的统一令牌(token),用于节点间认证。
通信层设计
- 双向通信机制:采用WebSocket + gRPC双通道
- WebSocket:用于实时指令推送和状态监控(长连接)
- gRPC:用于批量配置同步和大数据传输(高效序列化)
- 消息协议:Protobuf定义统一消息格式,确保前后端一致性
- 连接保持:客户端实现自动重连和心跳检测机制
配置管理策略
# 采用版本化配置管理
config_version: "1.0"
changes:
- id: "change_001"
timestamp: "2024-01-01T10:00:00Z"
operation: "add_mapping"
rollback_support: true
技术栈¶
服务端(UFMS)
| 组件 | 推荐技术 | 理由 |
|---|---|---|
| 后端框架 | Go (Gin/Echo) | 与Frp技术栈一致,部署简单,性能优异 |
| 前端框架 | Vue 3 + TypeScript + Vite | 生态成熟,开发效率高,适合管理后台 |
| 数据库 | PostgreSQL + Redis | 关系型存储配置 + 缓存会话状态 |
| 消息队列 | NATS JetStream | 轻量级,支持持久化,适合微服务 |
| API文档 | Swagger/OpenAPI | 自动生成接口文档 |
| 容器化 | Docker + Docker Compose | 简化部署 |
客户端(UFMC)
| 组件 | 推荐技术 | 理由 |
|---|---|---|
| 核心语言 | Go | 单二进制部署,无依赖,内存占用小 |
| 进程管理 | 使用os/exec + supervisor |
可靠管理frpc生命周期 |
| 配置解析 | viper库 | 支持多种格式,热加载配置 |
| 日志系统 | zap + lumberjack | 高性能日志,支持轮转 |
安全设计强化¶
- 认证与授权
// 基于JWT的访问控制
type AuthToken struct {
UUID string `json:"uuid"`
NodeID string `json:"node_id"`
Role string `json:"role"` // admin/node/readonly
Expiry int64 `json:"exp"`
Permissions []string `json:"perms"`
}
- 网络安全
- 传输加密:全链路TLS 1.3,双向证书认证
- 访问控制:基于角色的细粒度权限控制(RBAC)
- 审计日志:记录所有配置变更和操作历史
- 配置签名:所有下发的配置都附带数字签名,防止篡改
核心功能模块规划¶
- 配置管理中心
- 版本控制:每次变更生成快照,支持一键回滚
- 差异比较:可视化显示配置变更内容
-
批量操作:支持按标签分组批量配置
-
监控与告警
type NodeHealth struct {
CPUUsage float64 `json:"cpu_usage"`
MemoryUsage float64 `json:"mem_usage"`
NetworkStats Network `json:"network"`
FRPStatus string `json:"frp_status"` // running/stopped/error
LastSynced time.Time `json:"last_synced"`
}
- 自动发现与注册
# 支持多种节点发现方式
discovery:
manual: # 手动添加
auto_scan: # 网络扫描发现
api_import: # 从云平台API导入
agent_based: # 客户端主动上报
部署架构¶
┌─────────────────────────────────────────┐
│ 云服务端 (UFMS) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Web服务 │ │ API网关 │ │ 数据库 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────┬────────────────────────┘
│ HTTPS + WebSocket
┌─────────────┴─────────────┐
│ 防火墙/NAT │
┌───┴───┐ ┌─────┴────┐
│UFMC A │ │ UFMC B │
│内网服务器│ │内网服务器 │
└───┬───┘ └─────┬────┘
│ │
┌───┴───┐ ┌─────┴────┐
│ frpc │ │ frpc │
└───────┘ └──────────┘
性能优化考虑¶
- 配置增量同步:只传输变更部分,减少带宽
- 连接池管理:复用WebSocket连接,降低开销
- 本地缓存:客户端缓存配置,网络中断时可继续运行
- 并行操作:支持批量节点并行配置更新
兼容性设计¶
- 多版本Frp支持:适配不同版本的frpc/frps
- 跨平台客户端:支持Linux/Windows/macOS
- 配置导入导出:支持从现有frpc.ini/toml导入