# jo-frp **Repository Path**: duihao/jo-frp ## Basic Information - **Project Name**: jo-frp - **Description**: 一套内网穿透到外网的技术方案,基于frp实现便捷配置,一行短码直接实现穿透连接 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-11-01 - **Last Updated**: 2026-11-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # jo-frp > Duihao Jo! 开源计划 · 自建穿透的两件套 > 服务端一键部署,客户端扫码接入 —— 全程不需要编辑任何配置文件。 frp 很强,但它的门槛是三关:买服务器、跑命令装 frps、手写 toml。 jo-frp 把这三关压成两步:**服务端跑一条命令 → 客户端扫一个码**。 ``` 你的云服务器 你的电脑 / NAS ┌──────────────────┐ ┌──────────────────┐ │ jo-frp-server │ │ jo-frp-client │ │ ├ Web 管理面板 │ ←─ 短码 ─→ │ ├ 托盘图标 │ │ └ 内嵌 frps │ │ └ 内嵌 frpc │ └────────┬─────────┘ └────────┬─────────┘ │ frp 隧道(数据面) │ └───────────────┬─────────────────┘ ▼ 外网 http://你的IP:50000 → 家里的 NAS ``` **边界很清楚**:服务端只在发放短码时交换几十字节的信令, 业务流量始终在「你的客户端 ↔ 你的服务器」之间,不经过任何第三方。 --- ## 仓库结构 单仓两个可执行程序,共用底层包: ``` cmd/ server/ 服务端入口(部署在云服务器) client/ 客户端入口(Windows 托盘 / 其他平台控制台) internal/ api/ 服务端 HTTP 接口 client/ 客户端核心逻辑(与 UI 无关) frpcfg/ frpc 配置文件解析(导入 / 文件模式共用) frpctl/ frps / frpc 生命周期封装(嵌入官方 frp 库) shortcode/ 短码生成与归一化 store/ 服务端数据持久化 pkg/ api/ 客户端 ↔ 服务端的协议定义 web/ 服务端管理面板前端 ``` --- ## 快速开始 需要 **Go 1.22+**。 ### 1. 编译 ```bash make build # 输出到 bin/ # 或分别构建 go build -o bin/jo-frp-server ./cmd/server go build -o bin/jo-frp-client ./cmd/client ``` Windows 客户端(在 Linux 上交叉编译): ```bash make client-windows # 需要 mingw-w64:apt install gcc-mingw-w64-x86-64 ``` ### 2. 起服务端 在**你的云服务器**上: ```bash ./bin/jo-frp-server -addr :16686 -data ./data -web ./web ``` | 参数 | 说明 | 默认 | |---|---|---| | `-addr` | 面板监听地址 | `:16686` | | `-data` | 数据与日志目录 | `./data` | | `-web` | 前端静态目录 | `./web` | | `-demo` | 内嵌演示站点端口(仅调试用) | 关闭 | | `-selfcheck` | 启动内置 frpc 自检(会占一条映射端口) | 关闭 | 打开 `http://你的服务器IP:16686` → 点「+ 添加服务器」。 > 单机全流程试用:`-addr :16686 -demo 18080`, > 然后添加服务器(地址留空或填 127.0.0.1,控制端口填 0 自动分配)。 ### 3. 起客户端 Windows 双击 `jo-frp-client.exe`,托盘图标出现 → 右键「设置短码…」→ 填入服务端地址和短码,自动连接。 也可以命令行直连: ```bash jo-frp-client -panel http://47.98.123.45:16686 -code DH-7F3K-9X2A ``` 进程会一直保持运行(隧道活着),按 `Ctrl+C` 才断开。 `-once` 仅作 systemd / 容器的语义标记保留,行为已与默认一致。 Linux/macOS 上不带参数运行会进入控制台交互模式,逻辑完全一致。 ### 掉线会自动重连 客户端常驻监督循环,掉线后自己恢复,不需要人工点「重连」: ``` 掉线,正在重连… ← 1s 后开始,frp 内部按 1s→2s→4s…→20s 退避 掉线,第 2 次重连… ← 每 20s 递增,让用户看得出还在动 掉线,第 3 次重连… 已连接 我的节点,外网地址 1.2.3.4:50000 ``` 分工很明确,避免双层重连互相打架: | 层 | 负责什么 | |---|---| | frp 内部 | 真正的重连(1s 起步、×2、封顶 20s、10% 抖动) | | jo-frp 监督循环 | 只读 frp 的代理状态机来判断在线与否,**不重复做重连** | | 外层兜底 | 仅当 frpc 进程本身死掉,或掉线超过 90s 未恢复,才重建 | > 为什么外层不当"急性子":重建要重新拉配置、重新登录,会把 frp 已经走到的 > 20 秒退避拉回起点。实测抢着重连会变成每 2 秒重登一次,日志刷屏且隧道一直不通。 **主动断开永远是权威**:点「断开」或 `Ctrl+C` 后,监督循环立即退出, 不会被自动重连救回来。实现上靠世代号(generation)保证——每次 `Start`/`Stop` 都让旧循环看到自己过期。 --- ## 沿用你已有的 frpc 配置文件 已经有 `frpc.toml` / `frpc.ini` 的用户不必重录一遍,两条路都能走: | 方案 | 做法 | 适合谁 | |---|---|---| | **A · 导入面板** | 面板「导入 frpc 配置」粘贴/拖入文件,一次翻译成服务器 + 规则 | 想用面板统一管理,之后不再碰文件 | | **C · 纯文件模式** | 客户端 `-c frpc.toml` 直接读,完全不碰面板 | 已有配置流水线,文件就是唯一真相源 | ### A 方案:导入到面板 面板右上角 →「导入 frpc 配置」: - 支持 **toml 与 ini 两种格式**,走 frp 官方 `config.LoadClientConfig` 解析,不自己发明语法 - 粘贴、点击选文件、拖拽都行 - 点「预览」先看清楚要导入什么,再点「确认导入」 - 服务器地址建议填**真实公网 IP**:配置文件里的 `serverAddr` 常是 `127.0.0.1`,照搬会生成错的外网链接 导入规则: - 只认 **TCP / UDP**(有 `remotePort` 的)。`http`/`https`/`stcp` 走域名 vhost,面板暂无此概念,**如实跳过并提示条数**,不假装导入 - 远端端口是全局唯一的:冲突的规则跳过,**不覆盖**你已有的 - 同一 `addr` + `bindPort` 重复导入会**合并到同一台服务器**,不会建出两条 - `token` 和 `transport.tls.enable` 一并带过来 ```bash curl -X POST http://127.0.0.1:16686/api/import \ -H 'Content-Type: application/json' \ -d '{"content":"","dryRun":true}' # 预览 ``` `dryRun:true` 只解析不落库,返回翻译结果、冲突端口和告警。 ### C 方案:纯文件模式 ```bash jo-frp-client -c /etc/frp/frpc.toml ``` - 每轮重连都重新解析文件,**改完配置不用重启客户端**(下次重连即生效) - 完全不访问面板,面板挂了也不影响 - 与 `-panel`/`-code` 互斥,指定 `-c` 即进入文件模式 > 取舍:文件模式放弃了面板的可视化与热改规则能力,换来"配置即代码"的确定性。 > 想两者兼得就先导入(A),之后在面板里改。 --- ## 验证整条链路真的通 ```bash # 服务端加一条规则:本机 18080 → 远端 50000 # 然后: curl http://127.0.0.1:18080/ # 内网直连 curl http://127.0.0.1:50000/ # 经 frps 转发,应返回同一页面 ``` 两个都通 = 服务端、客户端、frps、frpc 四者协作无误。 --- ## 云服务器部署要点 1. **配置**:2核2G 足够(frps 是纯转发,带宽比核数重要) 2. **安全组放行**:控制端口 `7000/tcp` + 映射端口段(如 `50000-50100/tcp`) 3. **systemd**: ```ini [Unit] Description=jo-frp server After=network-online.target Wants=network-online.target [Service] Type=simple ExecStart=/opt/jo-frp/jo-frp-server -addr 127.0.0.1:16686 -data /var/lib/jo-frp -web /opt/jo-frp/web Restart=always RestartSec=3 LimitNOFILE=1048576 [Install] WantedBy=multi-user.target ``` > **安全提醒**:面板本身没有任何鉴权。请只监听 `127.0.0.1`, > 通过 SSH 隧道(`ssh -L 16686:127.0.0.1:16686 root@你的服务器`)访问。 --- ## HTTP 接口 | 方法 | 路径 | 说明 | |---|---|---| | GET | `/api/servers` | 服务器列表(含实时状态) | | POST | `/api/servers` | 新增并启动 frps | | DELETE | `/api/servers?id=` | 删除服务器及其规则 | | GET | `/api/proxies` | 规则列表 | | POST | `/api/proxies` | 新增规则 | | POST | `/api/proxies/toggle` | 启停规则 | | DELETE | `/api/proxies?id=` | 删除规则 | | POST | `/api/import` | 导入 frpc 配置(`dryRun` 可只预览) | | **GET** | **`/api/config?code=`** | **客户端凭短码拉配置(唯一下发接口)** | | GET | `/api/qrcode?code=` | 短码二维码 PNG | | GET | `/api/stats` | 概览统计 | | GET | `/install.sh` | 安装脚本 | `/api/config` 的响应就是全部信令:服务器地址、控制端口、token 和规则列表。 客户端拿到之后自己去连 frps —— 面板在这之后不再参与任何数据流动。 --- ## 设计取舍 | 决策 | 原因 | |---|---| | 嵌入 frp 库而非拉二进制 | 单一可执行文件;配置与状态进程内直读,无 IPC | | 短码 8 位、排除 `0O1IL` | 手输、口述、微信传都不易错 | | 二维码内容 = 短码本身 | 手机扫完直接得到字符串,不需要解析 URL | | 服务端不内置常驻 frpc | 否则会与真实客户端抢同一个远程端口(开发中实际踩到) | | 数据落单 JSON 文件 | 零依赖、零 CGO;这个量级用不上数据库 | | 客户端按平台拆分 UI | Windows 走 systray,其他平台走控制台,核心逻辑共用 | | 客户端连上后常驻不退 | 进程退出 = 隧道断掉;用信号量收尾,非 UI 场景也能安全停机 | | 重连交给 frp,外层只管状态 | frp 自带 1s→20s 退避,外层再包一层会让退避重置,反而更慢 | | 与 frp 内部重连不抢方向盘 | 只在 frpc 进程死掉或掉线 >90s 时才由外层重建,避免每 2 秒重登 | | 用世代号区分主动/被动断开 | `Stop` 是最强信号,旧监督循环靠 gen 过期自退,不会被自动重连救回来 | | 配置导入走 frp 官方解析器 | 自己写 toml/ini 解析必然与官方语义漂移,`.ini` 老格式还得手写兼容 | | 导入只认 TCP/UDP | `http`/`https` 靠域名 vhost,面板没有这个概念;与其半吊子支持不如说清楚 | | 导入不做覆盖写 | 端口冲突时跳过而非替换,避免一次手滑抹掉线上规则 | | 文件模式每轮重连重读文件 | 改完配置不必重启客户端,符合"配置即代码"的使用习惯 | --- ## 测试 ```bash make test ``` 覆盖短码归一化(14 组边界输入)、短码唯一性、接口校验、端口冲突、二维码、统计, 客户端退避策略(单调性、封顶、溢出)与致命错误分类, 以及配置导入(toml/ini 双格式、http 规则跳过、重复导入合并、端口冲突、`dryRun` 不落库)。 ### 实测自愈 ```bash # 客户端连上后,直接杀掉服务端 pkill -f jo-frp-server # 客户端会自己进入退避重连;服务端重启后自动恢复 # 判定标准:/api/config 只被请求 1 次(说明没有反复重建) grep -c "GET /api/config" srv.log # 应为 1 ``` --- ## 已知限制 - frpc 改配置采用**重建**而非热更新(毫秒级闪断)。生产可换 `client.Service.UpdateAllConfigurer` - 隧道全断时最长有约 20 秒空窗(受 frp 重连上限约束),无法更短 - **面板无鉴权**,默认假设只在内网 / SSH 隧道后访问 - 只有 TCP 映射;HTTP 域名映射(vhost)未做,导入时会被跳过并提示 - 无流量统计(需读 frps proxy 状态或接 metrics) - 导入是一次性翻译:导入后在面板里改,回头再改文件不会同步 --- ## 与 frp 的关系 穿透能力完全来自开源项目 [fatedier/frp](https://github.com/fatedier/frp)(Apache-2.0)。 jo-frp 是它之上的易用性封装,**非官方产品**。 ## License MIT