FRP 管理桌面客户端公版Mole部署教程

本文将带你从零开始,快速完成基于 Mole 的内网穿透服务部署,包含服务端 (frps) 与桌面客户端 (Mole/frpc) 的配置与排查要点。 📖 核心概念 什么是 FRP? FRP (Fast Reverse Proxy) 是一款高性能的反向代理/内网穿透工具,它通过在公网服务器和内网客户端之间建立隧道,使外网可以访问内网服务(如 NAS、树莓派、开发环境等)。 什么是 Mole? Mole 是一款基于 wails3 开发的 FRP 桌面客户端,提供图形化管理界面,简化 frpc 的配置与使用: 告别繁琐命令行 支持系统托盘常驻,防止误关窗口导致中断 支持 HTTP/HTTPS、TCP、UDP 等多种协议 🛠️ 部署前准备 一台拥有公网 IP 的低配云服务器(例如1核1G内存的阿里云、腾讯云等) FRP 服务端(frps)与客户端(frpc)二进制文件,建议使用 FRP Releases 的 v0.65.0 或更高版本 Mole 桌面客户端安装包(对应你操作系统的版本) 基本网络与防火墙管理权限 1. 服务端配置(frps) 在拥有公网IP的云服务器上部署frps服务端: 下载并解压 FRP 服务端(以 Linux 为例) 访问 FRP 的 Releases 页面下载对应版本并解压(示例为 v0.65.0 或更高)。 编写 frps.toml 配置文件(示例) 将以下内容写入 frps.toml,并根据实际需求调整端口与 token: bindPort = 7000 # 客户端连接端口(frpc 连接到此端口) vhostHTTPPort = 8080 # HTTP 映射的公网访问端口(可选) # 建议设置 auth.token 为复杂字符串,防止未授权连接 auth.token = "你的复杂密匙" 启动 frps(示例) 在服务端目录运行: ...

2026-01-07 · 2 min · Eagle

Wails 3 初体验及在FRP管理客户端中的应用

为什么选择了Wails 3 ? Wails 3 最大的改变在于它不再强绑定于某个特定的前端框架,且引入了多窗口支持和更轻量级的 Runtime。它允许你在不启动主窗口的情况下运行后端服务,这正是我们实现“系统托盘”和“后台演示服务”的基础。 在 v2 中,我们习惯于自动生成的 wailsjs 文件夹。但在 v3 中,这一逻辑被进一步标准化。 当你运行开发指令时,Wails 会扫描你的 Go 结构体方法,并将其映射为前端可以调用的 JavaScript 函数。这个过程在 v3 中被称为 Generate 过程。 Wails 3 通信灵魂 我们在前端调用在后端定义的 HandleConnect 返回自定义结构体,这在 Wails 3 中是前后端通信的灵魂。 在 Wails 3 开发中,最核心的动作就是:后端做功,前端表现。 当你调用 MoleService.HandleConnect() 时,Go 后端会产生一个结果。在本项目中,我们需要同时返回一个 Code(状态码)和一个 Content(数据内容)。 为了实现这一点,我们定义了一个结构体: type Response struct { Code int; Content string } 虽然 Go 内部使用的是结构体,但前端 JavaScript 只能读懂 JSON 对象。Wails 3 内部会自动帮你完成这个“翻译”过程。 但是,如果你想让前端看到的字段名是小写的(例如 res.code 而不是 res.Code),你必须在 Go 结构体定义时加上“注解”。 type Response struct { Code int `json:"code"` Content string `json:"content"` } 记住,所有通过 bindings 调用的 Go 方法,在前端返回的都是一个 Promise 对象。这意味着你必须使用 await 或者 .then() 来接收数据,否则你拿到的将是一个永不开启的“盲盒”。 ...

2025-11-01 · 3 min · Eagle

从单页网站开启数字创造

所有的宏大工程都始于最微小的表达。这一节,我们聊聊那个只有 index.html 的纯真时代。本文将带你了解数字世界背后的故事。 1. 域名的“翻译”艺术 服务器在网络中是以 IP 地址(如 123.123.123.123)存在的。为了让人类能够记忆,我们引入了域名系统(DNS)。 解析逻辑: 通过配置一条 A 记录,我们将 91demo.top 映射到特定的数字 IP 上。从此,枯燥的数字拥有了可读的身份。 2. 安全的阶梯:从 HTTP 到 HTTPS 一个现代化的网站不应“裸奔”。 使用 Let’s Encrypt 提供的免费证书,配合 Nginx 的反向代理配置,我们为网站穿上了 TLS 加密的铠甲。 成就达成: 浏览器地址栏那个小锁头的出现,标志着你已初步掌握了网络协议的基础。 3. 守门人:Nginx 的静默力量 在本项目中,没有繁琐的数据库和 API 逻辑。Nginx 扮演了一个纯粹的“守门人”角色。 它安静地运行在后台,监听着 80 与 443 端口,随时准备将那一个笨拙却真诚的 index.html 展示给世界。 “虽然 CSS 是 AI 生成的,但我终于学会了如何让代码在服务器上跳舞。” 4. 归于简单:单页的本质 现在的 Web 世界如迷宫般复杂,但回看那个单页网站,那不仅是 HTML,更是开发者第一次触碰数字创造的本质:用基础的材料,构建被看见的天地。

2025-03-02 · 1 min · Eagle

Rust 版本文章上传命令行工具

这个工具使用Rust开发,仅实现了上传文章功能,使用 GUI 桌面开发。 该工具使用的库为 nwg,即 native-windows-gui 库,该库支持老的 Windows GUI。 这应该算是一个半成品,这是 Rust 实现的一个桌面上传文章工具。它只有上传功能,之所以会这样,是因为后续的开发重心都放在go版本实现上。 不过这也有一定的价值,首先就是它实现了图形桌面,这个可以学会如何实现一个窗口,显示输入框和按钮,如何布局。然后呢,可以在Rust中使用HTTP上传文件,这也是一个非常棒的技能点。 以后有精力了,可以扩展完善一下。 项目地址 https://gitee.com/littletow/upart-rs

2023-08-21 · 1 min · Eagle

自助语音验证码介绍

版本:v1.0 创作时间:2024-08-19 21:40:00 自助语音验证码是通过 拨打 VOIP 电话自动获取验证码,验证码可用来豆子笔记网站认证。掌握了此项技术,你也可以应用于其它地方。 Asterisk 是一个流行的开源通信平台,它提供了构建各种通信应用的灵活而强大的解决方案。它被广泛应用于企业内部电话系统、呼叫中心、语音邮件等场景。 Asterisk 支持多种通信协议,包括 SIP、H.323、MGCP 和 SCCP,并且能够与传统的 PSTN 线路深度兼容。 此外,Asterisk 还支持通过 Inter-Asterisk eXchange (IAX)协议进行语音过 IP 传输,允许数据和语音同时在网络上传输。 我们使用 Asterisk 实现了自助语音验证码功能。 常用 VOIP 软件 手机端推荐:zoiper,linphone PC 端推荐:microsip,eyebeam,zoiper,linphone 自助语音验证码使用说明 你需要准备: 软电话,或者支持 VOIP 的电话机 AST 账户,AST 账户从豆子工具小程序中获取,功能菜单为获取 AST 账户。 注意:AST 账户获取后,需在次日才可以使用,因为申请账号的库和 Asterisk 不是同一个库。它会在凌晨进行自动同步。 首先,使用获取到的账户配置你的电话。 然后,拨打 8000,即可自动获取验证码。 如果您有什么问题,欢迎关注公众号【技术源泉】私信我。

2022-08-19 · 1 min · Eagle

八年了,从一个随机数按钮到我的技术底座:豆子工具复盘

有些事,不做笔记真的意识不到已经过去了这么久。 最近在整理博客内容时,我翻到了**“豆子工具”小程序**的最早版本记录。那是 2018 年,最初的它简陋得甚至有点滑稽:整个页面只有一个按钮,点一下,生成一个随机数。 谁能想到,这颗“小豆子”一跑就是八年。 八年,它长成了我最趁手的“瑞士军刀” 这八年里,我在这款小程序上倾注了太多的时间和精力。它更像是我个人开发者生涯的一个“活化石”,记录了我每一个阶段遇到的问题和想出的方案。 我始终坚持一个原则:只做真正有用的。 现在的“豆子工具”已经从当年的随机数生成器,进化成了一个覆盖网络、多媒体、开发调试的全能工具箱: 网络与运维必备:获取 WIFI 公网地址、云厂商安全组管理、查服务端口、域名证书检测。 多媒体处理:音频格式转换(m4a 转 mp3)、图片格式转换(png 转 webp)、二维码识别与生成。 开发调试利器:局域网调试(TCP/UDP/WebSocket)、ESP 网络配置、时间戳转换、Base64 与 URL 编解码。 安全与提醒:私密密码本、事件邮件通知、微信服务通知、语音验证码。 这中间还有很多功能,比如查看上报信息、特定的算法实现等。当然,也有不少功能因为受众太小或者微信审核的边界问题,遗憾地消失在了版本更迭中。 它是工具,也是我的技术底座 很多人问过我,市面上工具软件那么多,为什么要自己写? 答案很简单:自由。 我可以为了适配一个特殊的局域网协议去写一套调试代码,也可以为了保护自己的隐私数据写一个加密密码本。这八年积累下来的不只是功能,更是对 Go、Rust、前端交互以及各种底层协议的深度理解。 关于未来的“深度复盘” 八年的积淀太厚,小程序那方寸之间已经装不下太多的原理说明。 所以,我决定在我的新博客中,为这些工具开辟专门的专栏。我会挑选出其中含金量最高、逻辑最有趣的工具,拆解它们的实现原理。比如: 多媒体黑盒:音频和图片格式转换在小程序前端是如何高效完成的? 网络深水区:局域网内的协议调试有哪些不为人知的坑? 消息推送系统:我是如何设计那套多端触发的事件通知系统的? 这些内容我会以“实战笔记”的形式,在这里逐一连载。 这颗“豆子”还会继续长下去,而关于它的故事,我们去博客细聊。

2018-01-03 · 1 min · Eagle

使用 Wails v3 打造 frp 桌面客户端:mole-go 原理与跨端开发

一、 缘起:为什么需要 mole-go? 在开发微信公众号、调试支付接口、以及演示本地开发网站时,或由于服务器资源限制需要在本地部署服务时,frp 是不可或缺的内网穿透神器。然而,原生的 frpc 存在几个显著的痛点: 运行隐形性差:必须开启命令行窗口,一旦误关服务即中断。 配置门槛高:新手难以记忆复杂的 .toml 参数。 为了解决这些问题,我开发了 mole-go。它是一个轻量级、跨平台的桌面客户端,旨在实现 frp 的配置、启动与监控一体化。我选择 Wails v3 则是看中了其原生渲染、系统托盘支持、Go 强力后端以及极小的打包体积。 二、 核心架构:Go + Wails v3 的化学反应 mole-go 采用了经典的“UI-Backend-Service”三层架构: Wails UI:负责前端展示,通过事件驱动(Event-Driven)与后端交互。 Go Backend:核心大脑,负责业务逻辑、进程管理与系统级 API 调用。 frpc 二进制:底层服务,通过 Go 的 embed 特性内嵌到二进制文件中。 三、 关键实现细节:从命令行到图形化的进化 前端:从“面条代码”到模块化数据驱动 早期版本中,我直接采用 window.startFrp,window.stopFrp这样的写法,导致代码碎片化严重,以及管理app运行状态不方便。在 mole-go 的正式版中,我将其重构为数据驱动模式,类似Vue,由数据驱动界面: 模块化封装:定义全局 window.App 对象,将数据状态与行为(Methods)统一封装,使代码结构清晰。 动态 UI 组件:针对 HTTP、TCP、UDP 等不同代理模型,不再机械地堆砌 HTML 片段,而是通过逻辑判断实现“按需渲染”,大大精简了 DOM 结构。 后端:全局实例与事件机制 为了保证服务层(Service)能随时与 UI 通信,我设计了一个全局 App 实例,这样可以方便得调用和管理。 状态约定:前后端约定一套状态码,通过 Wails v3 的 Events 机制,后端可以主动向前端推送 frpc 的运行状态、日志等信息。 独立服务层:将 frp 相关逻辑抽离到专门的文件中,通过 Wails 的 Binding 暴露给前端,保持代码的解耦。 系统深度集成 系统托盘(System Tray):利用 Wails v3 原生的托盘支持,实现了“关闭即隐藏”逻辑。 外部链接调用:使用 wails3自带的 Browser.OpenURL 方法,确保点击文档链接时能正确唤起系统浏览器。 可参考项目源码。 ...

2026-01-10 · 1 min · Eagle

系列开篇:告别命令行的束缚,我为何选择 Wails v3 打造 frp 管理客户端?

一、困境与契机:低配服务器、高性能需求与共享经济的思考 我的云服务器配置很“复古”:1 核 CPU、1G 内存、1M 带宽。它完美地满足了我个人博客的需求,直到我需要演示一套视频会议系统。该系统最低要求 2 核 4G。 我的服务器是包年做活动时购买,升级配置成本高昂,而我的本地电脑性能过剩,为了一次演示,我升级我的云服务器,我感觉不值。为了解决这个问题,frp(Fast Reverse Proxy) 成为了我的救星,它允许我将本地高性能服务安全地映射到公网。 新的痛点出现:命令行的局限性 在成功通过命令行 frpc 实现了内网穿透演示后,我发现了一系列生产力问题: 进程管理难题: 命令行窗口一旦关闭,frpc 进程随之终止,服务中断。这在日常使用中非常不便,因为会经常手误关闭窗口。 潜在的商业价值: 我有闲置资源服务器,公网 IP 以及域名。对于那些临时需要公网映射的用户来说,这是一个刚需。 流量变现与服务化: 我有一个小程序并集成了广告。如果能让用户通过看广告来获取临时的 frps 使用权(子域名分配),可以减少我的服务器支出,这将是一个双赢的模式。 为了解决这些问题并实现我的想法,我意识到可以做一个稳定、可后台运行、拥有友好 UI 的客户端,来替代原始的命令行操作。 二、技术选型坎坷路:Fyne、Tauri 的尝试与碰壁 我的技术栈主要集中在 Go、Rust 和 JavaScript,其中 Go 最擅长。我希望使用这些技术栈实现一个跨平台的客户端。 第一次尝试:Go & Fyne Fyne 是一款使用 Go 语言编写的跨平台 GUI 库。我首先尝试了它。 优点: 纯 Go 编写,上手快。 痛点: 在处理 frpc 实时打印的日志时,Fyne 对中文字符的支持不理想;复杂的列表和表格布局实现起来很痛苦。最终放弃。 第二次尝试:Rust & Tauri Tauri 是当时(也是现在)非常热门的跨平台框架,结合 Rust 的后端性能和 Web 前端技术。 优点: 性能强劲,打包体积小,前端界面开发体验好。 痛点: 我完成了界面设计,但在核心的 frp 控制模块上遇到了巨大的技术难题。Rust 的所有权(Ownership) 和生命周期管理让我头疼不已,始终无法优雅地实现 frp 进程的启动、停止和状态共享。项目卡壳。 三、柳暗花明:Wails v3 成为“天选之子” 在技术选型陷入僵局时,有读者告诉我可以尝试下 wails 3,我关注了 Wails 项目的 v3 版本。虽然现在它还处于 Alpha 阶段,但它宣传的特性完美契合我的所有需求: ...

2025-12-01 · 1 min · Eagle

实战笔记:网站使用二维码登录

扫码基石:构建视觉化的连接钥匙 二维码(QR Code)是连接物理世界与数字世界的“虫洞”。在登录系统中,它承载着一个临时的身份信标。 1. 生成有效二维码 登录二维码通常包含一个加密的 URL 或一个唯一的 UUID(通用唯一识别码)。 唯一性: 每一对扫描动作都必须对应一个独一无二的 ID。 时效性: 二维码必须配合 Redis 设置过期时间(如 2 分钟),逾期自动失效。 Redis 最核心的用法是 Key-Value (键值对)。 在本项目中,我们将用户的微信 OpenID 作为 Key,生成的验证码作为 Value: // 存储验证码,并设置 5 分钟过期 err := rdb.Set(ctx, "user:123:code", "8888", 5*time.Minute).Err() // 读取验证码 val, err := rdb.Get(ctx, "user:123:code").Result() 在 Go 生态中,我们使用 skip2/go-qrcode 等库来完成像素的绘制: // 生成二维码字节数组 var png []byte png, _ = qrcode.Encode("91demo.top"+sessionID, qrcode.Medium, 256) 为了防止用户伪造扫码请求,二维码里的内容通常是加密的或者是不可预测的长随机数(UUID)。只有真实存在的 ID 才能通过后端的 Redis 校验。 2. 传输二维码 我们不希望在用户硬盘上产生大量的临时 .png 文件。 最佳实践是将二进制图片转换为 Base64 字符串,通过结构体返回给前端: // 转换为前端可直接识别的 Data URL base64Img := "data:image/png;base64," + base64.StdEncoding.EncodeToString(png) 为了让前端不至于崩溃,后端必须返回统一的格式。 func HandleLogin(c *gin.Context) { // 逻辑处理... c.JSON(200, gin.H{ "code": 1, "content": base64Img, }) } 在前端,我们不再需要引入沉重的第三方库来做简单的请求。浏览器原生提供的 Fetch API 简洁且基于 Promise。 ...

2025-03-15 · 3 min · Eagle

Go 版本文章上传命令行工具

这是 Golang 实现的上传文章以及管理文章的一个命令行工具。 项目地址 https://gitee.com/littletow/upart-go 实现一个上传文章的命令行工具 这是一个最初的版本,使用 flag 和 ini 来实现文章上传功能。使用 flag 来解析命令行参数,使用 Ini 配置文件,记录识别码,以及 token。记录 token 的原因是因为每次启动命令行,都需要重新获取 token,为了减少 token 获取次数,在获取到 token 后,同时存储到 Ini 配置文件中。每次命令行启动,优先查看配置文件中的 token。 开发这个工具主要有以下几个技术要点: 从命令行获取参数 从配置文件中读取参数 读取文件内容 请求后端接口 我们通过分析后,需要定义以下几个参数: title 标题 keyword 关键字 filename MD 文件名 ispub 是否公开 islock 是否加锁 使用 Go 代码定义参数和结构体 var ( title string keyword string filename string ispub int // 1 pub islock int // 1 lock ) func init() { flag.StringVar(&title, "b", "", "文章题目") flag.StringVar(&keyword, "k", "", "文章关键字") flag.StringVar(&filename, "f", "", "MD文件") flag.IntVar(&islock, "l", 0, "是否加锁") flag.IntVar(&ispub, "p", 0, "是否开放") } func main(){ flag.Parse() } init() 在 main 函数前调用。需要在 main 函数中调用 flag.Parse(),这一步非常关键。之后就可以使用变量了。 ...

2024-09-21 · 3 min · Eagle