From ff7c8155c8b4e7b008e8adf45c22f22d9d9f1f5b Mon Sep 17 00:00:00 2001 From: okxlin Date: Mon, 22 Jan 2024 11:38:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=B7=BB=E5=8A=A0frp-panel=E5=88=B0?= =?UTF-8?q?=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/frp-panel-master/0.0.11/.env.sample | 6 + apps/frp-panel-master/0.0.11/data.yml | 41 +++++ .../0.0.11/docker-compose.yml | 22 +++ apps/frp-panel-master/README.md | 171 ++++++++++++++++++ apps/frp-panel-master/data.yml | 20 ++ apps/frp-panel-master/latest/.env.sample | 6 + apps/frp-panel-master/latest/data.yml | 41 +++++ .../latest/docker-compose.yml | 22 +++ apps/frp-panel-master/logo.png | Bin 0 -> 4768 bytes apps/frp-panel/0.0.11/.env.sample | 2 + apps/frp-panel/0.0.11/data.yml | 9 + apps/frp-panel/0.0.11/docker-compose.yml | 10 + apps/frp-panel/README.md | 171 ++++++++++++++++++ apps/frp-panel/data.yml | 20 ++ apps/frp-panel/latest/.env.sample | 2 + apps/frp-panel/latest/data.yml | 9 + apps/frp-panel/latest/docker-compose.yml | 10 + apps/frp-panel/logo.png | Bin 0 -> 4768 bytes 18 files changed, 562 insertions(+) create mode 100644 apps/frp-panel-master/0.0.11/.env.sample create mode 100644 apps/frp-panel-master/0.0.11/data.yml create mode 100644 apps/frp-panel-master/0.0.11/docker-compose.yml create mode 100644 apps/frp-panel-master/README.md create mode 100644 apps/frp-panel-master/data.yml create mode 100644 apps/frp-panel-master/latest/.env.sample create mode 100644 apps/frp-panel-master/latest/data.yml create mode 100644 apps/frp-panel-master/latest/docker-compose.yml create mode 100644 apps/frp-panel-master/logo.png create mode 100644 apps/frp-panel/0.0.11/.env.sample create mode 100644 apps/frp-panel/0.0.11/data.yml create mode 100644 apps/frp-panel/0.0.11/docker-compose.yml create mode 100644 apps/frp-panel/README.md create mode 100644 apps/frp-panel/data.yml create mode 100644 apps/frp-panel/latest/.env.sample create mode 100644 apps/frp-panel/latest/data.yml create mode 100644 apps/frp-panel/latest/docker-compose.yml create mode 100644 apps/frp-panel/logo.png diff --git a/apps/frp-panel-master/0.0.11/.env.sample b/apps/frp-panel-master/0.0.11/.env.sample new file mode 100644 index 00000000..a653fa65 --- /dev/null +++ b/apps/frp-panel-master/0.0.11/.env.sample @@ -0,0 +1,6 @@ +CONTAINER_NAME="frp-panel-master" +DATA_PATH="./data" +PANEL_APP_PORT_HTTP="40195" +PANEL_APP_PORT_RPC="40196" +APP_GLOBAL_SECRET="U7eF38YJXA0f5pbTKBvF" +MASTER_RPC_HOST="0.0.0.0" diff --git a/apps/frp-panel-master/0.0.11/data.yml b/apps/frp-panel-master/0.0.11/data.yml new file mode 100644 index 00000000..7a4b49c8 --- /dev/null +++ b/apps/frp-panel-master/0.0.11/data.yml @@ -0,0 +1,41 @@ +additionalProperties: + formFields: + - default: 40195 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: Port (Internal 9000) + labelZh: 端口 (对应内部 9000) + required: true + rule: paramPort + type: number + - default: 40196 + edit: true + envKey: PANEL_APP_PORT_RPC + labelEn: RPC Port (Internal 9001) + labelZh: RPC 端口 (对应内部 9001) + required: true + rule: paramPort + type: number + - default: ./data + edit: true + envKey: DATA_PATH + labelEn: Data folder path + labelZh: 数据文件夹路径 + required: true + type: text + - default: '' + edit: true + envKey: APP_GLOBAL_SECRET + labelEn: Secret Keys + labelZh: 通信密钥 + random: true + required: true + rule: paramComplexity + type: password + - default: 0.0.0.0 + edit: true + envKey: MASTER_RPC_HOST + labelEn: The IP that RPC is listening on + labelZh: RPC 监听 IP + required: true + type: text diff --git a/apps/frp-panel-master/0.0.11/docker-compose.yml b/apps/frp-panel-master/0.0.11/docker-compose.yml new file mode 100644 index 00000000..cbd4f571 --- /dev/null +++ b/apps/frp-panel-master/0.0.11/docker-compose.yml @@ -0,0 +1,22 @@ +version: '3' +services: + frp-panel-master: + container_name: ${CONTAINER_NAME} + restart: always + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTP}:9000" + - "${PANEL_APP_PORT_RPC}:9001" + volumes: + - "${DATA_PATH}:/data" + environment: + - APP_GLOBAL_SECRET=${APP_GLOBAL_SECRET} + - MASTER_RPC_HOST=${MASTER_RPC_HOST} + image: vaalacat/frp-panel:v0.0.11 + labels: + createdBy: "Apps" + +networks: + 1panel-network: + external: true diff --git a/apps/frp-panel-master/README.md b/apps/frp-panel-master/README.md new file mode 100644 index 00000000..6848c9c6 --- /dev/null +++ b/apps/frp-panel-master/README.md @@ -0,0 +1,171 @@ +> 详细博客地址: [https://vaala.cat/2024/01/14/frp-panel-doc/](https://vaala.cat/2024/01/14/frp-panel-doc/) +> 使用说明可以看博客,也可以直接滑到最后 + +# FRP-Panel + +我们的目标就是做一个: +- 客户端配置可中心化管理 +- 多服务端配置管理 +- 可视化配置界面 +- 简化运行所需要的配置 + +的更强更完善的frp! + +- demo Video: [demo Video](https://github.com/VaalaCat/frp-panel/blob/main/doc/frp-panel-demo.mp4) + + +## 项目开发指南 + +### 平台架构设计 + +技术栈选好了,下一步就是要设计程序的架构。在刚刚背景里说的那样,frp本身有frpc和frps(客户端和服务端),这两个角色肯定是必不可少了。然后我们还要新增一个东西去管理它们,所以frp-panel新增了一个master角色。master会负责管理各种frpc和frps,中心化的存储配置文件和连接信息。 + +然后是frpc和frps。原版是需要在两边分别写配置文件的。那么既然原版已经支持了,就不用在走原版的路子,我们直接不支持配置文件,所有的配置都必须从master获取。 + +其次还要考虑到与原版的兼容问题,frp-panel的客户端/服务端都必须要能连上官方frpc/frps服务。这样的话就可以做到配置文件/不要配置文件都能完美工作了。 +总的说来架构还是很简单的。 + +![arch](https://github.com/VaalaCat/frp-panel/raw/main/doc/arch.png) + +### 开发 + +项目包含三个角色 +1. Master: 控制节点,接受来自前端的请求并负责管理Client和Server +2. Server: 服务端,受控制节点控制,负责对客户端提供服务,包含frps和rpc(用于连接Master)服务 +3. Client: 客户端,受控制节点控制,包含frpc和rpc(用于连接Master)服务 + +接下来给出一个项目中各个包的功能 +``` +. +|-- biz # 主要业务逻辑 +| |-- client # 客户端逻辑(这里指的是frp-panel的客户端) +| |-- master # frp-panel 控制平面,负责处理前端请求,并且使用rpc管理frp-panel的server和client +| | |-- auth # 认证模块,包含用户认证和客户端认证 +| | |-- client # 客户端模块,包含前端管理客户端的各种API +| | |-- server # 服务端模块,包含前端管理服务端的各种API +| | `-- user # 用户模块,包含用户管理、用户信息获取等 +| `-- server # 服务端逻辑(这里指的是frp-panel的服务端) +|-- cache # 缓存,用于存储frps的认证token +|-- cmd # 命令行入口,main函数的所在地,负责按需启动各个模块 +|-- common +|-- conf +|-- dao # data access object,任何和数据库相关的操作会调用这个库 +|-- doc # 文档 +|-- idl # idl定义 +|-- middleware # api的中间件,包含JWT和context相关,用于处理api请求,鉴权通过后会把用户信息注入到context,可以通过common包获取 +|-- models # 数据库模型,用于定义数据库表。同时包含实体定义 +|-- pb # protobuf生成的pb文件 +|-- rpc # 各种rpc的所在地,包含Client/Server调用Master的逻辑,也包含Master使用Stream调用Client和Server的逻辑 +|-- services # 各种需要在内存中持久运行的模块,这个包可以管理各个服务的运行/停止 +| |-- api # api服务,运行需要外部传入一个ginRouter +| |-- client # frp的客户端,即frpc,可以控制frpc的各种配置/开始与停止 +| |-- master # master服务,包含rpc的服务端定义,接收到rpc请求后会调用biz包处理逻辑 +| |-- rpcclient # 有状态的rpc客户端,因为rpc的client都没有公网ip,因此在rpc client启动时会调用master的stream长连接rpc,建立连接后Master和Client通过这个包通信 +| `-- server # frp的服务端,即frps,可以控制frps的各种配置/开始与停止 +|-- tunnel # tunnel模块,用于管理tunnel,也就是管理frpc和frps服务 +|-- utils +|-- watcher # 定时运行的任务,比如每30秒更新一次配置文件 +`-- www + |-- api + |-- components # 这里面有一个apitest组件用于测试 + | `-- ui + |-- lib + | `-- pb + |-- pages + |-- public + |-- store + |-- styles + `-- types + +``` + +### 调试启动方式: + +- master: `go run cmd/*.go master` +> client 和 server 的具体参数请复制 master webui 中的内容 +- client: `go run cmd/*.go client -i -s ` +- server: `go run cmd/*.go server -i -s ` + +项目配置文件会默认读取当前文件夹下的.env文件,项目内置了样例配置文件,可以按照自己的需求进行修改 + +## 项目使用说明 +frp-panel可选docker和直接运行模式部署,直接部署请到release下载文件:[release](https://github.com/VaalaCat/frp-panel/releases) + +启动过后默认访问地址为 http://IP:9000 + +### docker + +注意⚠️:client 和 server 的启动指令可能会随着项目更新而改变,虽然在项目迭代时会注意前后兼容,但仍难以完全适配,因此 client 和 server 的启动指令以 master 生成为准 + +- master + +```bash +docker run -d -p 9000:9000 \ + -p 9001:9001 \ + --restart=unless-stopped \ + -v /opt/frp-panel:/data \ + -e APP_GLOBAL_SECRET=your_secret \ # Master的secret注意不要泄漏,客户端和服务端的是通过Master生成的 + -e MASTER_RPC_HOST=0.0.0.0 \ + vaalacat/frp-panel +# 或者 +docker run -d \ + --network=host \ + --restart=unless-stopped \ + -v /opt/frp-panel:/data \ + -e APP_GLOBAL_SECRET=your_secret \ # Master的secret注意不要泄漏,客户端和服务端的是通过Master生成的 + -e MASTER_RPC_HOST=0.0.0.0 \ + vaalacat/frp-panel +``` +- client + +```bash +docker run -d \ + --network=host \ + --restart=unless-stopped \ + vaalacat/frp-panel client -s xxx -i xxx # 在master WebUI复制的参数 +``` +- server + +```bash +docker run -d \ + --network=host \ + --restart=unless-stopped \ + vaalacat/frp-panel server -s xxx -i xxx # 在master WebUI复制的参数 +``` + +### 直接运行(Linux) +- master + +``` +APP_GLOBAL_SECRET=your_secret MASTER_RPC_HOST=0.0.0.0 frp-panel master +``` +- client + +``` +frp-panel client -s xxx -i xxx # 在master WebUI复制的参数 +``` +- server + +``` +frp-panel server -s xxx -i xxx # 在master WebUI复制的参数 +``` +### 直接运行(Windows) +在下载的可执行文件同名文件夹下创建一个 `.env` 文件(注意不要有后缀名),然后输入以下内容保存后运行对应命令,注意,client和server的对应参数需要在web页面复制 + +- master: `frp-panel-amd64.exe master` +``` +APP_GLOBAL_SECRET=your_secret +MASTER_RPC_HOST=IP +DB_DSN=data.db +``` + +client 和 server 要使用在 master WebUI复制的参数 + +- client: `frp-panel-amd64.exe client -s xxx -i xxx` + +- server: `frp-panel-amd64.exe server -s xxx -i xxx` + +### 配置说明 + +[settings.go](https://github.com/VaalaCat/frp-panel/blob/main/conf/settings.go) +这里有详细的配置参数解释,需要进一步修改配置请参考该文件 diff --git a/apps/frp-panel-master/data.yml b/apps/frp-panel-master/data.yml new file mode 100644 index 00000000..05757335 --- /dev/null +++ b/apps/frp-panel-master/data.yml @@ -0,0 +1,20 @@ +name: FRP-Panel (Master) +tags: + - 工具 +title: 多节点 FRP WebUI (控制节点) +type: 工具 +description: 多节点 FRP WebUI (控制节点) +additionalProperties: + key: frp-panel-master + name: FRP-Panel (Master) + tags: + - Tool + shortDescZh: 多节点 FRP WebUI (控制节点) + shortDescEn: A multi node frp webui (Console) + type: tool + crossVersionUpdate: true + limit: 0 + recommend: 0 + website: https://github.com/VaalaCat/frp-panel + github: https://github.com/VaalaCat/frp-panel + document: https://github.com/VaalaCat/frp-panel diff --git a/apps/frp-panel-master/latest/.env.sample b/apps/frp-panel-master/latest/.env.sample new file mode 100644 index 00000000..a653fa65 --- /dev/null +++ b/apps/frp-panel-master/latest/.env.sample @@ -0,0 +1,6 @@ +CONTAINER_NAME="frp-panel-master" +DATA_PATH="./data" +PANEL_APP_PORT_HTTP="40195" +PANEL_APP_PORT_RPC="40196" +APP_GLOBAL_SECRET="U7eF38YJXA0f5pbTKBvF" +MASTER_RPC_HOST="0.0.0.0" diff --git a/apps/frp-panel-master/latest/data.yml b/apps/frp-panel-master/latest/data.yml new file mode 100644 index 00000000..7a4b49c8 --- /dev/null +++ b/apps/frp-panel-master/latest/data.yml @@ -0,0 +1,41 @@ +additionalProperties: + formFields: + - default: 40195 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: Port (Internal 9000) + labelZh: 端口 (对应内部 9000) + required: true + rule: paramPort + type: number + - default: 40196 + edit: true + envKey: PANEL_APP_PORT_RPC + labelEn: RPC Port (Internal 9001) + labelZh: RPC 端口 (对应内部 9001) + required: true + rule: paramPort + type: number + - default: ./data + edit: true + envKey: DATA_PATH + labelEn: Data folder path + labelZh: 数据文件夹路径 + required: true + type: text + - default: '' + edit: true + envKey: APP_GLOBAL_SECRET + labelEn: Secret Keys + labelZh: 通信密钥 + random: true + required: true + rule: paramComplexity + type: password + - default: 0.0.0.0 + edit: true + envKey: MASTER_RPC_HOST + labelEn: The IP that RPC is listening on + labelZh: RPC 监听 IP + required: true + type: text diff --git a/apps/frp-panel-master/latest/docker-compose.yml b/apps/frp-panel-master/latest/docker-compose.yml new file mode 100644 index 00000000..42476b25 --- /dev/null +++ b/apps/frp-panel-master/latest/docker-compose.yml @@ -0,0 +1,22 @@ +version: '3' +services: + frp-panel-master: + container_name: ${CONTAINER_NAME} + restart: always + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTP}:9000" + - "${PANEL_APP_PORT_RPC}:9001" + volumes: + - "${DATA_PATH}:/data" + environment: + - APP_GLOBAL_SECRET=${APP_GLOBAL_SECRET} + - MASTER_RPC_HOST=${MASTER_RPC_HOST} + image: vaalacat/frp-panel:latest + labels: + createdBy: "Apps" + +networks: + 1panel-network: + external: true diff --git a/apps/frp-panel-master/logo.png b/apps/frp-panel-master/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9cec3e62d1817bf3fe702d0d21ccdd15beb049a2 GIT binary patch literal 4768 zcmV;R5?}3!P)jbaz0;>2SrtTwn z)H1E<6|nIfMA{#)@DVcPBd_i=ZPq7b*aVQ=DY5Pzci0(h))HveB68OhgW4TK;2AyS zBR=37iQ5q&-xx{y0kHG{i`f8%*aIc!0CLy^Eam`g*8zFh0f5*89p?dM*a14?0yE?Q zUfBUw+5te|0Z!ZiklO)A-Ud4LYx6xd0000XbW%=J06iXX(G4#H{Qi$>R_ar^=A=Y? z`hl*|>X+iP&Xvja=Uoc^!vFvgdPzhopiyCwmZ88QH4lWH^WzlzO}Do-^o zG86ad{=WP0SY^N~LR^j|cbF5!i)YpDKR~n|<@)eG9$JHHC+u z!M(djZt_vB>;D~WjK3;H*7n7F0(&%S-TxJ9>-Z}UIQp6XNJQ%RJ1-r7g6vVfkXn=--}4@RcYp{Upn^i)nATC8hV}rzHarg_a`X!ksrx_IxPlM+F#3gvG&5M>cwqMA;7NGo$09Nxf1&#u zU__37Dk4K8{z@KE^^rdlk@(%p!Q2=I?ERTIBJDYEaNFMRU@fW&ahekhyO0>SIkHl}1BiAzV2ZyQH9xeZ5_zYc% zeandC@mDK~KRA5!n!dKJu;H`6yl0*)dRHEkw~9y{3XAb)Haj83CQZ}n%k_>C-e~v% z&3tkwBJy^9BzIlyT>SaN4K~I-yetyDE`I;`m?HKtXR+J$ku?5ltsHU~cQ&%6>HF}4 zNbK?UD?^?FHDiB|3nTId^GF?kF#gPm(`LwPXcD{AICC_#5#z-s#O~y*eTzPl51B=K zsASC?y{^~$^_oy`rqjZRL>n>IbSfL?evJwv@(cYfpNh(q5oD1oFARCV-V1JNl4+WY zNHlY2I%Ux+vAIj$vk|H1k>&bGI%VZwRwn)!EpL)~t-L*~!QFC)khZIJnTG_ElBxJ~3%Z4!gZFpeF?0S;e`<&XK9Bt7n zVyFC)rW@4yBPC*=k4TF|VszR0lo7@UY$rucxJ4%EFpttN6l35&z((Ya^fgV{@41Nd zL`06R4z@3*49Eh5gKivqZ^+HC3p#VmHbQKG-b}gHDgp9#E+R)FkrZ27r;J)r%82^A z!*0i}5?P6@vCj;fLc`iRiI~nVib!+%dwG>BGiJeq3S>cjAP$k_nRv>)yRx?6)>2O| zL}Ykrfrb70a6V;JlHGPEo2E9beRklX?FH6GJC+{g~0N zwp#<7aI@=S&~Te(sLm!OLy>7-?QBF!H#Fs=@T;jjhD~Fzg0@|)B(pF#;f~$sp`x?N zV}H=3UC>7&X3N(?k7_}NStGBA+NMjAax;FML@;bUVpU>O>~~{C!0z2aFm}ZenWIM! zUTDVOYBgW21UK~vQp1nkOYoIdQ|N5cG&QkJXY+_8FM0w;@D;59(qM%q6F-@+=InBg z8^8zcFU^@nXG2Ufofbsoi@|jVyGZWXozQF6YokZ{w_q@z8_ap^K^%T@;SDwc#Q)`} z4O@dpjDaqAqKnYoI=?5Gqq%H~d&`ZD*l?5FV);sRHp(T1S%d{7^@q?m^d9OYlK}H< zPO(>1Zn)X@f*UOqiq0k#*g6(7)H*ja)GFSi&@8bGW~@nMCH7WYWYv#uwoN1W~qG&9FcG~y7#oZS920}lU`vlTWC z$yZM+U02X`1>Ku1xYRQ<91*>tytW9k#q-K|n zFQMxNN&~c@p7RT~Qf3ZIbvAS|BdmQDdcmQ!*sKkrpW7=Cb*7XWJpK7$1HF*ZIOpV1 zxzqMRDeN}w&v_(TDZL=RW^ECaT9l7gl`@uU(_rM}pSDVC>_sVP&+D&}ve2g1AJ^@% zTo8xwo1oOeS!Yx!5sYnP5P~{?+CodM7iE?1L#JO3IS=c%~v+H0rg(mP^X+2d=_OlUQvO-ewM(~iLXX#>5? za4!Sb1IJ_-?j|)?nre+J@0Rvp%mRDqth6uIO>i8ZxIz=H}r#0^?d zlYDKVv|*5?8?+D_TH^I)&Qf!w*905EuPZ$TKM>5%p%=)>eBuU8x9M!`>@gwO z3rA=obmaM7BB<@9=FoyV-NMIdIyc2JrL%}3!qJc}k5GJB5DN^9W|3#ARQ*-rN>AME;Sc!Ca?wzyN&0d%&;i=qRk_)GT0#@Ct)Yd`jQd%iDr?Kt zSGzZ1FHn0bHTN~>$(S;O-1bU?(AXj+bm+aIJ!Y0tbLhQkkj=&tT4PTpwjwoV0=iF{ zI$37*E(pEX`&ZYt&|{O@-W~%zt(?&YN?S@zl-6p0UWZmvyD5!AFZ1h{l6z()wNQG$ zHdBa&J;sC@nx#GZdSaf@zmS#*^NUflaXk6PsBl6e< z+VlE+mLnE0-3@QG>|_tGuU1QzNgz)m;z_Znr?LB1(43k|Z3Rua$Je1zXx^UVY#AJzcJ-7=u1O8h zC#Ce>4ch2qER^mG}@z};5-Wx;i1?SI)V@x(7Ci@mjpNu*K_~)SX*iPxtYv!z6 ze0u+`N9G5Ypiic+EtEc*=CDvYiG7RBAegz6o|V$Hgl2zL>9L{o*a{lIe5)}PnA^hB zT4|y7Rp_Gz78je&#bI}Z6|~fv*W%ejb5DtMB`6G>vFc!IeUaT=wl{(G=J>B#9@aSp0E_f;68Q2t4aej1^?Il zp^aCt6Y`K_J{3Vf(S3Pn4^wM)x!LC9E7`C?%J4MysSuhdeMF^?V-tHkNq%56Vf1=X zC00hohwZVP@&zp)Dot8qm6s zAvnrr_?kO}S$lcY^oRA1W>FX^z&r6DiGtJB7Ze)40`2OfnXTor!p+hjmW=3Xwp>N5 zD0kFPf1rg7by}SBAgFV;R@}Eqe=s9RRGm_`+>y5(GAluKaSphfmO+IN$0FjuM zJ^hJFSY2L43u5^dosy6Pg|aj*^zImR&DgYaf6OPo%(~OE_vQblE9lF*!Btjk(aW$) z!y_Jmf-_M^6t)<(S=tx89gC9)T?THHPk-o)e7U1pTFQ|7fr0g?swhPfWyLH=Z2Z&M zMM?wpb4ibcyhd|NYuRLFDWx7X%yPsg6kK;@-wl=fRr3j+&zvo>Gjkce;9j=C0ctdh zs|I&E`MffJ^nwOuXT zH%s`s5IC!s)k8}OC?#$@LwAdk>T|y zT%l*ANc0R-u=f@AIg(!QPXTf;&F=4{MIZkT;7u^I7mZkLG`l^Ua;I}UFh#;MUo@HZ z@S4@e1!oOc7NLp`O(SL>FQ6tEp*@+q%tyUH|^d<9*r?r2wNffYi&}1&)zq<}R-se=Kr>in zr06QWT$p6cJoPosQgPlcAv={967SdKRu?ZXlCBNMsb62LIny}z1@+H1JQA|G<49>9 za0*)E7+H)>5(NY`zmA)n#0@^>He^B&T)C<|QS= zfuj2m;&w&%3AC3Jl9P07>(^&gZQ>cE$MK6Vwl3?Gl2M1$*Fj87r;HpVWQ7Fd(XDk$ zKiakbiTQz7QQ%_3KdibDy9_27!|9_A5iOaZAS5!QV{+8VrupDThih$&wQJrb8F?^B zDTBSHB4B6883c7qr;u%L%; zN#vWF(Ln7Psl9v~`l}#qmEvUd9#6kxJot93d70XWJE6prr{2V|p30`EomF1v9}Aay z!qE(&kkn(u%M|gKm)fsO0mfuC>9~>52XC4XM^4$B<@EQeY=eI7TjsXRFZY-;lEcwW z21gM;(oJgi(x2MPD~8axE%Uy*+w2@R*s01L_cKBM%NCN1gWO%?FP_>RM|W5-U3p|3 zJt7?3Re#KVV$%?OaT^U2ly@?TbJuRF=sw+!lfSVR(Men9;7r1scDERsx~X3VM_ zS`i-qNHSSG(PUVY+RgEIX{

!}0k@$uIak@e=yjlY=N3BnWaKW~gk*dW)%cD3KH zwneSf(5a7)G8=QG9&G%o^pIm^L|i@bbY{D?PdIy50b`l(y!p* u)zeQLhv-{v{-Yu3Xm({aFaH6 详细博客地址: [https://vaala.cat/2024/01/14/frp-panel-doc/](https://vaala.cat/2024/01/14/frp-panel-doc/) +> 使用说明可以看博客,也可以直接滑到最后 + +# FRP-Panel + +我们的目标就是做一个: +- 客户端配置可中心化管理 +- 多服务端配置管理 +- 可视化配置界面 +- 简化运行所需要的配置 + +的更强更完善的frp! + +- demo Video: [demo Video](https://github.com/VaalaCat/frp-panel/blob/main/doc/frp-panel-demo.mp4) + + +## 项目开发指南 + +### 平台架构设计 + +技术栈选好了,下一步就是要设计程序的架构。在刚刚背景里说的那样,frp本身有frpc和frps(客户端和服务端),这两个角色肯定是必不可少了。然后我们还要新增一个东西去管理它们,所以frp-panel新增了一个master角色。master会负责管理各种frpc和frps,中心化的存储配置文件和连接信息。 + +然后是frpc和frps。原版是需要在两边分别写配置文件的。那么既然原版已经支持了,就不用在走原版的路子,我们直接不支持配置文件,所有的配置都必须从master获取。 + +其次还要考虑到与原版的兼容问题,frp-panel的客户端/服务端都必须要能连上官方frpc/frps服务。这样的话就可以做到配置文件/不要配置文件都能完美工作了。 +总的说来架构还是很简单的。 + +![arch](https://github.com/VaalaCat/frp-panel/raw/main/doc/arch.png) + +### 开发 + +项目包含三个角色 +1. Master: 控制节点,接受来自前端的请求并负责管理Client和Server +2. Server: 服务端,受控制节点控制,负责对客户端提供服务,包含frps和rpc(用于连接Master)服务 +3. Client: 客户端,受控制节点控制,包含frpc和rpc(用于连接Master)服务 + +接下来给出一个项目中各个包的功能 +``` +. +|-- biz # 主要业务逻辑 +| |-- client # 客户端逻辑(这里指的是frp-panel的客户端) +| |-- master # frp-panel 控制平面,负责处理前端请求,并且使用rpc管理frp-panel的server和client +| | |-- auth # 认证模块,包含用户认证和客户端认证 +| | |-- client # 客户端模块,包含前端管理客户端的各种API +| | |-- server # 服务端模块,包含前端管理服务端的各种API +| | `-- user # 用户模块,包含用户管理、用户信息获取等 +| `-- server # 服务端逻辑(这里指的是frp-panel的服务端) +|-- cache # 缓存,用于存储frps的认证token +|-- cmd # 命令行入口,main函数的所在地,负责按需启动各个模块 +|-- common +|-- conf +|-- dao # data access object,任何和数据库相关的操作会调用这个库 +|-- doc # 文档 +|-- idl # idl定义 +|-- middleware # api的中间件,包含JWT和context相关,用于处理api请求,鉴权通过后会把用户信息注入到context,可以通过common包获取 +|-- models # 数据库模型,用于定义数据库表。同时包含实体定义 +|-- pb # protobuf生成的pb文件 +|-- rpc # 各种rpc的所在地,包含Client/Server调用Master的逻辑,也包含Master使用Stream调用Client和Server的逻辑 +|-- services # 各种需要在内存中持久运行的模块,这个包可以管理各个服务的运行/停止 +| |-- api # api服务,运行需要外部传入一个ginRouter +| |-- client # frp的客户端,即frpc,可以控制frpc的各种配置/开始与停止 +| |-- master # master服务,包含rpc的服务端定义,接收到rpc请求后会调用biz包处理逻辑 +| |-- rpcclient # 有状态的rpc客户端,因为rpc的client都没有公网ip,因此在rpc client启动时会调用master的stream长连接rpc,建立连接后Master和Client通过这个包通信 +| `-- server # frp的服务端,即frps,可以控制frps的各种配置/开始与停止 +|-- tunnel # tunnel模块,用于管理tunnel,也就是管理frpc和frps服务 +|-- utils +|-- watcher # 定时运行的任务,比如每30秒更新一次配置文件 +`-- www + |-- api + |-- components # 这里面有一个apitest组件用于测试 + | `-- ui + |-- lib + | `-- pb + |-- pages + |-- public + |-- store + |-- styles + `-- types + +``` + +### 调试启动方式: + +- master: `go run cmd/*.go master` +> client 和 server 的具体参数请复制 master webui 中的内容 +- client: `go run cmd/*.go client -i -s ` +- server: `go run cmd/*.go server -i -s ` + +项目配置文件会默认读取当前文件夹下的.env文件,项目内置了样例配置文件,可以按照自己的需求进行修改 + +## 项目使用说明 +frp-panel可选docker和直接运行模式部署,直接部署请到release下载文件:[release](https://github.com/VaalaCat/frp-panel/releases) + +启动过后默认访问地址为 http://IP:9000 + +### docker + +注意⚠️:client 和 server 的启动指令可能会随着项目更新而改变,虽然在项目迭代时会注意前后兼容,但仍难以完全适配,因此 client 和 server 的启动指令以 master 生成为准 + +- master + +```bash +docker run -d -p 9000:9000 \ + -p 9001:9001 \ + --restart=unless-stopped \ + -v /opt/frp-panel:/data \ + -e APP_GLOBAL_SECRET=your_secret \ # Master的secret注意不要泄漏,客户端和服务端的是通过Master生成的 + -e MASTER_RPC_HOST=0.0.0.0 \ + vaalacat/frp-panel +# 或者 +docker run -d \ + --network=host \ + --restart=unless-stopped \ + -v /opt/frp-panel:/data \ + -e APP_GLOBAL_SECRET=your_secret \ # Master的secret注意不要泄漏,客户端和服务端的是通过Master生成的 + -e MASTER_RPC_HOST=0.0.0.0 \ + vaalacat/frp-panel +``` +- client + +```bash +docker run -d \ + --network=host \ + --restart=unless-stopped \ + vaalacat/frp-panel client -s xxx -i xxx # 在master WebUI复制的参数 +``` +- server + +```bash +docker run -d \ + --network=host \ + --restart=unless-stopped \ + vaalacat/frp-panel server -s xxx -i xxx # 在master WebUI复制的参数 +``` + +### 直接运行(Linux) +- master + +``` +APP_GLOBAL_SECRET=your_secret MASTER_RPC_HOST=0.0.0.0 frp-panel master +``` +- client + +``` +frp-panel client -s xxx -i xxx # 在master WebUI复制的参数 +``` +- server + +``` +frp-panel server -s xxx -i xxx # 在master WebUI复制的参数 +``` +### 直接运行(Windows) +在下载的可执行文件同名文件夹下创建一个 `.env` 文件(注意不要有后缀名),然后输入以下内容保存后运行对应命令,注意,client和server的对应参数需要在web页面复制 + +- master: `frp-panel-amd64.exe master` +``` +APP_GLOBAL_SECRET=your_secret +MASTER_RPC_HOST=IP +DB_DSN=data.db +``` + +client 和 server 要使用在 master WebUI复制的参数 + +- client: `frp-panel-amd64.exe client -s xxx -i xxx` + +- server: `frp-panel-amd64.exe server -s xxx -i xxx` + +### 配置说明 + +[settings.go](https://github.com/VaalaCat/frp-panel/blob/main/conf/settings.go) +这里有详细的配置参数解释,需要进一步修改配置请参考该文件 diff --git a/apps/frp-panel/data.yml b/apps/frp-panel/data.yml new file mode 100644 index 00000000..12526ffd --- /dev/null +++ b/apps/frp-panel/data.yml @@ -0,0 +1,20 @@ +name: FRP-Panel (Server/Client) +tags: + - 工具 +title: 多节点 FRP WebUI (服务端/客户端) +type: 工具 +description: 多节点 FRP WebUI (服务端/客户端) +additionalProperties: + key: frp-panel + name: FRP-Panel (Server/Client) + tags: + - Tool + shortDescZh: 多节点 FRP WebUI (服务端/客户端) + shortDescEn: A multi node frp webui (Server/Client) + type: tool + crossVersionUpdate: true + limit: 0 + recommend: 0 + website: https://github.com/VaalaCat/frp-panel + github: https://github.com/VaalaCat/frp-panel + document: https://github.com/VaalaCat/frp-panel diff --git a/apps/frp-panel/latest/.env.sample b/apps/frp-panel/latest/.env.sample new file mode 100644 index 00000000..7ceddda2 --- /dev/null +++ b/apps/frp-panel/latest/.env.sample @@ -0,0 +1,2 @@ +CONTAINER_NAME="frp-panel" +COMMAND_LINE='' diff --git a/apps/frp-panel/latest/data.yml b/apps/frp-panel/latest/data.yml new file mode 100644 index 00000000..11cb42b9 --- /dev/null +++ b/apps/frp-panel/latest/data.yml @@ -0,0 +1,9 @@ +additionalProperties: + formFields: + - default: '' + edit: true + envKey: COMMAND_LINE + labelEn: Command parameters (Determined by the control node) + labelZh: 命令参数 (由控制节点决定,注意修改具体) + required: true + type: text diff --git a/apps/frp-panel/latest/docker-compose.yml b/apps/frp-panel/latest/docker-compose.yml new file mode 100644 index 00000000..028f7169 --- /dev/null +++ b/apps/frp-panel/latest/docker-compose.yml @@ -0,0 +1,10 @@ +version: '3' +services: + frp-panel: + container_name: ${CONTAINER_NAME} + restart: always + network_mode: host + command: ${COMMAND_LINE} + image: vaalacat/frp-panel:latest + labels: + createdBy: "Apps" diff --git a/apps/frp-panel/logo.png b/apps/frp-panel/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9cec3e62d1817bf3fe702d0d21ccdd15beb049a2 GIT binary patch literal 4768 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

!}0k@$uIak@e=yjlY=N3BnWaKW~gk*dW)%cD3KH zwneSf(5a7)G8=QG9&G%o^pIm^L|i@bbY{D?PdIy50b`l(y!p* u)zeQLhv-{v{-Yu3Xm({aFaH6