# FRP 管理平台 - 详细设计方案

> 版本：v1.0
> 日期：2026-05-25

---

## 一、概述

### 1.1 目标

搭建一个 Web 管理平台，通过页面可视化地管理 FRP 服务端（frps）和客户端（frpc）的隧道配置，实现新增/修改/删除配置后即时生效。

### 1.2 适用场景

| 机器 | FRP 角色 | 配置位置 | 系统 |
|------|---------|---------|------|
| 阿里云 (120.26.66.182) | frps 服务端 | /etc/frp/frps.ini | CentOS 7 |
| 内网旧 Windows (192.168.31.77) | frpc 客户端 | 本地目录 | Windows |
| 内网新 Windows | frpc 客户端 | 本地目录 | Windows |
| 内网 Debian (192.168.31.182) | frpc 客户端（已停） | /etc/frp/frpc.toml | Debian 13 |

---

## 二、数据库设计

### 2.1 表结构

#### frp_server（服务端）

| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT PK | 主键 |
| name | VARCHAR(64) | 名称，如"阿里云 FRP" |
| host | VARCHAR(64) | IP 或域名 |
| bind_port | INT | 绑定端口，默认 7000 |
| token | VARCHAR(128) | 认证 token |
| dashboard_port | INT | 仪表盘端口，默认 7500 |
| dashboard_user | VARCHAR(64) | 仪表盘用户名 |
| dashboard_pwd | VARCHAR(128) | 仪表盘密码 |
| vhost_http_port | INT | HTTP 虚拟主机端口 |
| remark | TEXT | 备注 |
| status | TINYINT | 0=停用 1=启用 |
| created_at | DATETIME | |
| updated_at | DATETIME | |

#### frp_client（客户端）

| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT PK | 主键 |
| server_id | BIGINT FK | 关联 frp_server |
| name | VARCHAR(64) | 名称，如"内网旧Windows" |
| host | VARCHAR(64) | 内网 IP |
| config_path | VARCHAR(256) | 配置文件路径 |
| config_format | VARCHAR(16) | ini / toml |
| ssh_host | VARCHAR(64) | SSH 管理地址 |
| ssh_port | INT | SSH 端口，默认 22 |
| ssh_user | VARCHAR(64) | SSH 用户 |
| ssh_pwd | VARCHAR(256) | SSH 密码（加密存储） |
| os_type | VARCHAR(16) | linux / windows |
| frpc_cmd | VARCHAR(256) | frpc 重启命令 |
| status | TINYINT | 0=停用 1=启用 |
| created_at | DATETIME | |
| updated_at | DATETIME | |

> **frpc 重启命令参考：**
> - Linux + systemd：`systemctl restart frpc`
> - Windows：`sc stop frpc && timeout /t 2 && sc start frpc`
> - Linux + 进程：`pkill frpc && frpc -c /etc/frp/frpc.toml &`

#### frp_tunnel（隧道）

| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT PK | 主键 |
| client_id | BIGINT FK | 关联 frp_client |
| name | VARCHAR(64) | 隧道名，如"rdp" |
| type | VARCHAR(16) | tcp / udp / http / https |
| local_ip | VARCHAR(64) | 本地 IP，默认 127.0.0.1 |
| local_port | INT | 本地端口 |
| remote_port | INT | 远程端口 |
| use_encryption | TINYINT | 是否加密 |
| use_compression | TINYINT | 是否压缩 |
| status | TINYINT | 0=停用 1=启用 |
| remark | TEXT | 备注 |
| created_at | DATETIME | |
| updated_at | DATETIME | |

### 2.2 E-R 关系

```
frp_server 1 ──── N frp_client 1 ──── N frp_tunnel
```

---

## 三、API 接口设计

### 3.1 服务端管理

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /api/server/list | 列表 |
| GET | /api/server/{id} | 详情 |
| POST | /api/server | 新增 |
| PUT | /api/server/{id} | 修改 |
| DELETE | /api/server/{id} | 删除 |
| POST | /api/server/{id}/deploy | 部署配置到远程 |
| POST | /api/server/{id}/restart | 重启 frps |
| GET | /api/server/{id}/status | 获取运行状态 |

### 3.2 客户端管理

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /api/client/list | 列表 |
| GET | /api/client/{id} | 详情 |
| POST | /api/client | 新增 |
| PUT | /api/client/{id} | 修改 |
| DELETE | /api/client/{id} | 删除 |
| POST | /api/client/{id}/deploy | 部署配置到远程 |
| POST | /api/client/{id}/restart | 重启 frpc |
| GET | /api/client/{id}/status | 获取运行状态 |
| POST | /api/client/{id}/test-ssh | 测试 SSH 连接 |

### 3.3 隧道管理

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /api/tunnel/list?clientId=xxx | 按客户端查隧道列表 |
| GET | /api/tunnel/{id} | 隧道详情 |
| POST | /api/tunnel | 新增 |
| PUT | /api/tunnel/{id} | 修改 |
| DELETE | /api/tunnel/{id} | 删除 |

### 3.4 配置生成与部署

| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /api/deploy/frps/{serverId} | 生成+部署 frps.ini |
| POST | /api/deploy/frpc/{clientId} | 生成+部署 frpc 配置 |
| POST | /api/deploy/all | 一键部署所有配置 |
| GET | /api/deploy/preview/frps/{serverId} | 预览 frps.ini |
| GET | /api/deploy/preview/frpc/{clientId} | 预览 frpc 配置 |

---

## 四、配置生成逻辑

### 4.1 frps.ini（INI 格式）

```ini
[common]
bind_port = 7000
token = YourStrongToken!
dashboard_port = 7500
dashboard_user = admin
dashboard_pwd = ****
vhost_http_port = 80
allow_ports = 3381-3384, 7500, 8081, 18080, 18081, 2000-3000
log_file = /var/log/frps/frps.log
log_level = info
```

### 4.2 frpc.toml（TOML 格式，新版）

```toml
serverAddr = "120.26.66.182"
serverPort = 7000
auth.token = "YourStrongToken!"

[[proxies]]
name = "rdp"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3389
remotePort = 3381

[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 3382
```

### 4.3 配置差异处理

| 格式 | 适用场景 | 服务端 | 客户端 |
|------|---------|--------|--------|
| INI | 旧版 frp (< 0.52.0) | frps.ini | frpc.ini |
| TOML | 新版 frp (>= 0.52.0) | 不适用 | frpc.toml |

服务端始终用 INI 格式（frps 不支持 TOML）。客户端根据 `config_format` 字段决定生成 INI 还是 TOML。

---

## 五、部署与生效流程

### 5.1 新增隧道完整流程

```
用户新增隧道 → 存入数据库
  → 查询该客户端所有隧道 → 生成完整 frpc 配置
  → SSH 上传配置到目标机器
  → SSH 执行重启命令（frpc restart）
  → 验证隧道是否在线 → 返回结果
```

### 5.2 删除隧道流程

```
用户删除隧道 → 数据库删除
  → 重新生成配置
  → SSH 上传 + 重启
  → 返回结果
```

### 5.3 SSH 连接池

```
Java Spring Boot
  └── JSch (SSH 库)
       ├── frpc-旧Windows (ssh://root01@120.26.66.182:3382)
       ├── frpc-新Windows (ssh://...)
       └── frpc-Debian (ssh://root01@120.26.66.182:3383)
```

- 每个客户端用 SSH 隧道地址管理
- 连接池复用，避免频繁创建

---

## 六、页面原型设计

### 6.1 页面结构

```
┌─────────────────────────────────────────┐
│  FRP 管理平台          [用户] [退出]    │
├─────────────────────────────────────────┤
│  ┌─────────┐ ┌─────────┐ ┌──────────┐ │
│  │ 服务端   │ │ 客户端  │ │ 隧道     │ │
│  │ 管理     │ │ 管理    │ │ 管理     │ │
│  │ (3个)    │ │ (3个)   │ │ (6条)    │ │
│  └─────────┘ └─────────┘ └──────────┘ │
├─────────────────────────────────────────┤
│                                         │
│  主操作区域                              │
│                                         │
│  (列表 / 表单 / 详情)                    │
│                                         │
└─────────────────────────────────────────┘
```

### 6.2 核心交互

**服务端卡片视图：**
```
┌─ 阿里云 FRP ────────────────┐
│ ✅ 运行中   120.26.66.182   │
│ 仪表盘 :7500  绑定 :7000   │
│ [编辑] [查看隧道] [重启]    │
└────────────────────────────┘
```

**隧道列表（以客户端分组）：**
```
内网旧 Windows (3条隧道)
┌──────────────────────────────┐
│ rdp     TCP  3389→3381  ✅   │
│ ssh     TCP  22→3382   ✅   │
│ [新增] [部署] [重启]         │
└──────────────────────────────┘
```

**新增隧道表单：**
```
名称: [rdp-dev        ]
类型: [TCP ▼]
本地IP: [127.0.0.1        ]
本地端口: [8080              ]
远程端口: [18080             ]
加密: [□] 压缩: [□]
备注: [                  ]
[保存] [取消]
```

---

## 七、技术实现

### 7.1 技术栈

| 层 | 技术 |
|----|------|
| 后端框架 | Spring Boot 3.x |
| 数据库 | MySQL / H2 |
| ORM | MyBatis-Plus |
| SSH | JSch (Java SSH 客户端) |
| 前端 | Vue 3 + Element Plus |
| 构建 | Maven |
| 部署 | Docker |

### 7.2 项目结构

```
frp-manager/
├── src/main/java/com/frpmanager/
│   ├── controller/        # REST 控制器
│   │   ├── ServerController.java
│   │   ├── ClientController.java
│   │   ├── TunnelController.java
│   │   └── DeployController.java
│   ├── service/           # 业务逻辑
│   │   ├── FrpConfigService.java     # 配置生成
│   │   ├── SshService.java           # SSH 连接管理
│   │   └── DeployService.java        # 部署流程编排
│   ├── model/             # 实体类
│   │   ├── FrpServer.java
│   │   ├── FrpClient.java
│   │   └── FrpTunnel.java
│   ├── mapper/            # MyBatis Mapper
│   ├── config/            # 配置
│   │   └── SshPoolConfig.java
│   └── util/
│       ├── ConfigGenerator.java  # INI/TOML 生成器
│       └── SshExecutor.java      # SSH 执行器
├── src/main/resources/
│   ├── application.yml
│   └── mapper/
├── frontend/              # Vue3 前端
└── Dockerfile
```

### 7.3 关键工具类

**ConfigGenerator** — 配置生成核心：
```
ConfigGenerator
├── generateFrpsIni(List<Tunnel>) → String
├── generateFrpcToml(List<Tunnel>) → String
└── generateFrpcIni(List<Tunnel>) → String
```

**SshExecutor** — SSH 远程执行：
```
SshExecutor
├── uploadFile(String content, String remotePath)  // 上传配置文件
├── execCommand(String command)                    // 执行命令
├── testConnection()                                // 测试连接
└── restartFrp(String osType)                      // 重启 frp (适配 Win/Linux)
```

---

## 八、安全考虑

| 风险 | 措施 |
|------|------|
| SSH 密码泄露 | 数据库加密存储（AES），页面脱敏显示 |
| API 未授权 | Spring Security + JWT 登录 |
| SQL 注入 | MyBatis-Plus 参数绑定 |
| 误操作改崩 | 部署前先备份旧配置（加 `.bak.时间戳`） |
| 端口冲突 | 新增隧道时校验远程端口是否已被占用 |

---

## 九、部署

### Docker 部署

```dockerfile
FROM eclipse-temurin:21-jre-jammy
WORKDIR /app
COPY target/frp-manager.jar app.jar
EXPOSE 18082
ENTRYPOINT ["java", "-jar", "app.jar"]
```

```yaml
# docker-compose.yml
services:
  frp-manager:
    image: frp-manager
    ports:
      - "18082:18082"
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://host.docker.internal:3306/frp_manager
      SPRING_DATASOURCE_USERNAME: tools
      SPRING_DATASOURCE_PASSWORD: ***
    restart: unless-stopped
```

### 访问路径

```
正式：https://tools.marschat.online/frp-manager/
或者独立域名：https://frp.marschat.online:18082
```

---

## 十、一键安装流程

### 10.1 安装触发入口

在客户端页面加一个「一键安装 FRP」按钮：

```
┌─ 内网新 Windows ────────────────┐
│ SSH: root@192.168.31.??:22       │
│ 状态: ❌ 未安装                  │
│                                  │
│ [一键安装 FRP] [测试SSH] [删除]  │
└──────────────────────────────────┘
```

### 10.2 安装流程图

```
用户点击「一键安装 FRP」
  ↓
SSH 连接到目标机器
  ↓
检测系统类型和架构
  ├── uname -m  → amd64 / arm64 / 386
  └── uname -s  → Linux / Windows (通过检测 PATH/环境变量)
  ↓
自动匹配正确的 frp 包
  ├── Linux amd64  → frp_0.65.0_linux_amd64.tar.gz
  ├── Linux arm64  → frp_0.65.0_linux_arm64.tar.gz
  ├── Linux 386    → frp_0.65.0_linux_386.tar.gz
  └── Windows      → frp_0.65.0_windows_amd64.zip
  ↓
下载安装包
  ├── 优先从龙虾主机 Nginx HTTP 下载（http://49.51.245.134/frp_xxx.tar.gz）
  └── 兜底从 GitHub Releases 下载
  ↓
安装（区分 Linux / Windows）
  ↓
生成配置文件
  ↓
注册为系统服务
  ↓
启动 frp
  ↓
验证连接状态 → 返回结果给页面
```

### 10.3 Linux 安装脚本（SSH 远程执行）

```bash
# 平台自动检测
ARCH=$(uname -m)
case $ARCH in
  x86_64)  PKG=frp_0.65.0_linux_amd64.tar.gz ;;
  aarch64) PKG=frp_0.65.0_linux_arm64.tar.gz ;;
  i386|i686) PKG=frp_0.65.0_linux_386.tar.gz ;;
esac

# 下载
curl -sL http://49.51.245.134/$PKG -o /tmp/$PKG

# 解压
tar xzf /tmp/$PKG -C /tmp/

# 复制二进制
cp /tmp/frp_*/frpc /usr/local/bin/frpc
chmod +x /usr/local/bin/frpc

# 写入配置（由 Java 动态生成）
cat > /etc/frp/frpc.toml << 'EOF'
[此处由 Java 动态生成配置内容]
EOF

# 注册 systemd 服务
cat > /etc/systemd/system/frpc.service << 'UNIT'
[Unit]
Description=FRP Client
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.toml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
UNIT

# 启动
systemctl daemon-reload
systemctl enable frpc
systemctl restart frpc
```

### 10.4 Windows 安装脚本

```batch
REM 通过 SSH 执行 Windows 命令
REM 创建目录
if not exist "C:\frp" mkdir C:\frp

REM 下载（Windows 用 certutil 或 powershell）
powershell -Command "Invoke-WebRequest -Uri http://49.51.245.134/frp_0.65.0_windows_amd64.zip -OutFile C:\frp\frp.zip"

REM 解压
powershell -Command "Expand-Archive -Path C:\frp\frp.zip -DestinationPath C:\frp\ -Force"

REM 复制二进制
copy C:\frp\frp_*/frpc.exe C:\frp\frpc.exe

REM 写入配置（由 Java 动态生成）
echo [此处由 Java 动态生成配置内容] > C:\frp\frpc.toml

REM 注册为 Windows 服务
sc create frpc binPath= "C:\frp\frpc.exe -c C:\frp\frpc.toml" start= auto
sc start frpc
```

### 10.5 安装进度反馈

因为安装过程可能耗时较长（下载+解压），需要做异步进度反馈：

```
API: POST /api/client/{id}/install
返回: { taskId: "xxx" }

轮询: GET /api/install-progress/{taskId}
返回: { step: "下载中...", progress: 45% }
       { step: "解压中...", progress: 60% }
       { step: "配置中...", progress: 80% }
       { step: "启动中...", progress: 95% }
       { step: "完成", progress: 100%, success: true }
```

前端通过 WebSocket 或轮询展示实时进度条。

---

## 十一、工作量估算

| 模块 | 人天 |
|------|------|
| 数据库设计 + 建表 | 0.5天 |
| 后端 CRUD + 配置生成 + SSH | 2天 |
| 前端页面（Vue3） | 2天 |
| 部署联调 + SSH 调试 | 1天 |
| **合计** | **约 5.5 天** |

---

## 十一、扩展思路

后续可加的功能：
- **隧道流量监控** — 定期调用 FRP API 获取流量数据，图表展示
- **在线/离线告警** — 隧道掉线时发飞书/微信通知
- **配置版本管理** — 每次部署自动备份，支持回滚
- **批量导入** — 从现有 frpc 配置文件中导入隧道
