实战:为 Hugo 博客开发一个公网 IP 探测 Shortcode
工具说明:在进行内网穿透(如调试 mole-go)或配置服务器白名单时,频繁查询公网 IP 是刚需。为了告别繁琐的登录和搜索,我开发了这个集成在博客中的实时探测组件。 🌐 公网 IP 探测 🌐 当前公网 IP: 正在探测... 复制 🛠️ 核心实现逻辑 这个工具基于 Hugo 的 Shortcode 功能实现,采用了异步加载技术,确保不会影响页面的首屏渲染速度。 ...
工具说明:在进行内网穿透(如调试 mole-go)或配置服务器白名单时,频繁查询公网 IP 是刚需。为了告别繁琐的登录和搜索,我开发了这个集成在博客中的实时探测组件。 🌐 公网 IP 探测 🌐 当前公网 IP: 正在探测... 复制 🛠️ 核心实现逻辑 这个工具基于 Hugo 的 Shortcode 功能实现,采用了异步加载技术,确保不会影响页面的首屏渲染速度。 ...
一、困境与契机:低配服务器、高性能需求与共享经济的思考 我的云服务器配置很“复古”: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 阶段,但它宣传的特性完美契合我的所有需求: ...
在上一篇文章中,我介绍了 Mole 客户端的业务闭环。今天,我们切入代码层面,聊聊基于 Wails 3 的 Go 后端是如何驱动 frp 核心并保证体验平滑的。 一、 Wails 3 项目启动架构 Wails 3 的启动逻辑高度模块化。在 main.go 中,一切从 application.New 开始。 1. 资产集成与服务绑定 首先,我们需要通过 embed.FS 将前端生成物(Vite 构建后的 dist 目录)打包进二进制文件: //go:embed all:frontend/dist var assets embed.FS func main() { app := application.New(application.Options{ Name: "Mole", Description: "Fast Reverse Proxy Manager", Services: []application.Service{ application.NewService(&FrpService{}), // 绑定核心服务 }, Assets: application.AssetOptions{ Handler: application.AssetFileServerFS(assets), }, }) // 创建窗口逻辑... } 关键点: Services 是 Wails 3 的精髓。它是一个切片,支持绑定多个服务实例。每个服务中定义的公开方法,前端都可以通过自动生成的 JS 绑定直接调用。 二、 核心经验总结:从“能跑”到“好用” 在开发 Mole 的原型过程中,我踩了不少坑,总结出以下 5 个核心经验: ...
我日常涉及 Hugo 博客发布、客户端打包、Nginx 运维等多种重复性脚本。每次都要 SSH 连服务器并执行命令,操作链过长,也不方便,特别是在身边没有电脑的情况。所以我就想构建一个通用的执行引擎,通过小程序远程触发,且具备零前端修改的扩展能力。 系统架构设计 为了实现“明天增加脚本,小程序不发版”的目标,采用了“配置驱动” 模式。即“配置在云端,指令在指尖”。通过将业务逻辑(脚本路径与名称)完全从前端小程序中解耦,实现一套代码支持无限扩展的运维能力。 核心流程 后端 (Go):维护一个脚本配置列表(数据库或配置文件)。 前端 (小程序):启动时请求后端接口,拉取可用脚本列表。 触发:使用时选择脚本名称,点击执行。 鉴权:后端校验小程序 OpenID,仅允许本人指令生效。 技术实现 系统分为三层,确保安全性与扩展性的统一: 配置层 (Go Config):在服务器端定义脚本的 ID、名称和实际路径。 鉴权层 (WeChat Auth):利用微信小程序 OpenID 建立强一致性的身份白名单。 展示层 (Mini Program UI):动态拉取后端配置,仅负责“展示列表”与“触发指令”。 技术实现方案 A. 后端:动态脚本引擎 (Go) 后端不再硬编码脚本路径,而是定义一个结构体: // 脚本任务定义 type ScriptTask struct { ID string `json:"id"` // 前端传递的任务标识 Name string `json:"name"` // 小程序界面显示的文字 Command string `json:"-"` // 实际执行的脚本路径 (对前端保密) } // 示例配置(可存放在 JSON 文件或数据库中) var tasks = []ScriptTask{ {ID: "hugo-post", Name: "发布 Hugo 文章", Command: "/scripts/deploy_hugo.sh"}, {ID: "build-client", Name: "构建客户端", Command: "/scripts/build_mole_go.sh"}, {ID: "nginx-restart", Name: "重启 Nginx 服务", Command: "systemctl restart nginx"}, } 对外接口定义: ...
在运维工作中,有一类事故极其低级却又杀伤力巨大:SSL 证书过期。 痛点:被动挨打的“救火”模式 由于业务需要,我手里管理着大量客户的域名。每个客户购买证书的渠道各异(阿里云、腾讯云或其他厂商),证书下来后通过微信或邮件发给运维,再手动配置到服务器上。 这套流程在客户少的时候还算正常。但随着客户增多,问题出现了:证书到期时间不一,全靠人工记忆。 总会有那么一两次,因为忙碌或者交接疏忽,某个域名证书悄悄过期了。直到客户反馈 APP 无法访问、浏览器弹出红色的安全告警,我们才急忙去“救火”。这种被动的局面不仅影响专业度,也给客户带来了实际损失。 方案:主动出击的自动化巡检 为了彻底根治这个“心病”,我决定做一个自动化的域名证书检测工具。 我的设想很简单:变“人找信息”为“信息找人”。 1. 实现原理 配置简单化:将所有需要监测的域名汇总成一个 txt 文件,每行一个域名,管理起来极其方便。 核心引擎(Go):使用 Go 语言开发后端服务,利用 cron 库开启定时任务,设定每天固定时间(如凌晨 4 点)执行一次巡检。 检测逻辑:程序自动循环读取域名列表,通过 TLS 握手获取证书的有效载荷,计算当前的剩余天数。 精准预警:我设定了一个“7天阈值”。一旦发现有域名将在 7 天内过期,程序会立即将这些域名汇总。 2. 消息触达:为什么选择机器人? 在小程序中,邮箱属于敏感隐私资料,审核往往比较严格。为了避开这个麻烦,同时也为了让通知更具实时性,我选择了钉钉机器人和企业微信机器人。 管理员或运营人员只需将机器人的 Webhook 地址配置好,每天早上一上班,就能在手机上收到一份清晰的到期清单。 价值:买到了最宝贵的“时间” 这个功能上线后,我们最直接的收获就是**“沟通时间”**: 提前预判:有了 7 天的缓冲期,运营人员可以气定神闲地与客户沟通续费。 提前操作:运维人员有了充裕的时间更换新证书,彻底杜绝了“半夜修证书”的尴尬。 总结 很多时候,自动化并不是为了追求多么高大上的技术,而是为了把人从那种机械、高风险的记忆工作中解放出来。 这个小工具的逻辑虽然简单,但它是我内容生态中非常重要的一环。它验证了:只要抓住了痛点,简单的技术组合也能产生巨大的生产力。
我从事于 IT 工作,经常会碰到各种奇葩的问题。其中的一项就是服务无法访问,当碰到这些情况,如何快速的排查问题?如果手边有电脑,那还好办,直接打开电脑找问题即可。如果手边没有电脑,我们怎么快速的定位问题?是服务挂掉了?还是服务器宕机了? 我的基本思路是这样的,先查看服务器是否宕机,如果服务器没有宕机,那么查看服务是否挂掉?如果服务没有挂掉,那么很大可能是数据造成的问题,或者程序 Bug。 某次我急需确认服务器上的一个端口是否正常开启,习惯性地打开 Windows 命令行准备敲下 telnet 命令。结果弹出的却是:“telnet 不是内部或外部命令”。这是让我抓狂的一刻。 由于系统刚重装,这个组件还没勾选。当我从控制面板找到它、安装、甚至可能还要重启系统时,这套复杂的操作让我陷入了反思:为了检测一个端口,至于这么麻烦吗? 更进一步想,如果我手头没有电脑,只有一部手机,我该如何快速判断服务器防火墙是不是忘了开? 痛点:环境依赖与生态限制 在实现这个功能之前,我有过两个思考维度: 环境依赖:无论是 Windows 的 Telnet 还是 Linux 的 nc,都依赖当前操作系统的环境配置。 小程序限制:微信小程序虽然有网络请求能力,但它必须配置服务器域名白名单。如果你想直接用小程序前端去探测一个随机的 IP 或端口,微信的底层安全机制是不允许的。 方案:Go 后端代劳,小程序只做“遥控器” 为了绕过这些限制,我在“豆子工具”里实现了一个远程端口检测功能。它的逻辑非常直接且高效: 前端交互:用户只需在小程序里输入目标服务器的 IP/域名 和 端口号。 后端核心:数据提交到我用 Go 编写的后端服务。 模拟连接:后端服务代替用户执行 TCP 连接探测。Go 语言的 net.DialTimeout 在这里非常实用,可以精准控制探测时间,避免由于网络超时导致的页面死等。 结果反馈:后端将“连接成功”或“连接失败”的结果返回给小程序展示。 那么如何操作呢? 1,访问服务器的 SSH 端口,查看是否通畅?如果程序返回开启,那么进行下一步。 2,访问服务端口,查看是否挂掉?如果程序返回开启,那么进行下一步。 3,查看其他用户是否这样的情况?如果是,大概率是程序 Bug,如果不是,大概率给这个用户的数据相关。 价值:随时随地的“运维眼” 自从这个功能上线后,我解决了很多尴尬的场景: 排查防火墙:在云厂商后台改了安全组策略后,掏出手机点一下,秒知是否生效。 现场交付:在客户现场没有电脑时,快速确认后端服务是否已经拉起。 零部署成本:再也不用担心当前电脑有没有装 Telnet 或 Netcat。 总结 很多时候,工具的意义并不在于它用了多么高深的算法,而在于它是否能在你最需要的时候,以最简单的方式解决那个微小却刺手的痛点。 这个小功能的背后,其实是 Go 语言并发网络模型的一个微小缩影。
在“流量贵如油”的今天,作为一名自己买服务器、撸代码的站长,如何给服务器“减负”是每天都要思考的必修课。 痛点:博客网站的流量杀手 我有一个运行多年的个人博客。在分析服务器日志时发现,最大的流量开销并不是文字,而是文章里那些高清的图片。 虽然 JPG 和 PNG 已经很普及,但随着屏幕分辨率越来越高,原图动辄几 MB,对于按带宽付费或者流量计费的服务器来说,这都是白花花的银子。 方案:Webp 格式的“降维打击” WebP是一种现代图片格式,由Google开发,主要目的是优化网页加载速度。它在2010年发布,并且可以提供比传统JPEG、PNG和GIF格式更高效的压缩和更好的图像质量。 它的特性如下: 高压缩效率:无损压缩情况下,WebP无损压缩后的图片文件大小通常比PNG小20-30%,同时可以完整地恢复原始图像数据。有损压缩情况下,WebP有损压缩后的图片质量与JPEG相似,但文件大小可以缩减25-34%,从而能在不牺牲太多图像质量的情况下减小文件体积。 支持透明度:WebP格式支持8位透明度通道(Alpha Channel),这允许图片在有损压缩的同时也能够处理透明背景,这是JPEG格式不具备的能力。 动画支持:WebP格式可以存储动画,功能类似于GIF,但是以更小的文件体积和更好的压缩效率。 广泛的颜色表示:WebP支持丰富的颜色表示方式,包括4:2:0和4:4:4色度采样。 兼容性和支持:WebP格式得到了许多现代浏览器如Chrome、Firefox、Edge等的支持。对于不支持WebP的浏览器,需要使用其他格式的图片作为替代。 文件扩展名是.webp。在Internet媒体类型(MIME type)中,WebP的类型是image/webp。 现在主流浏览器(Chrome, Safari, Edge 等)已经全面支持 Webp 格式。相比于传统的 JPG 和 PNG,Webp 可以在保证肉眼看不出画质损失的前提下,将文件体积压缩 30% 到 70%。 这是一个非常惊人的数据。这意味着原本 100GB 的图床流量,换成 Webp 后可能只需要 30GB。 为了方便处理博客素材,我决定把这个需求也集成到“豆子工具”里。 比如我的Hugo网站,在写文章用户图片时,我经常会截屏作为我的图片源,或者拍照作为我的图片源。这个在微信上传时自动转为JPG格式。虽然进行了压缩,但是体积还是有几百KB甚至达到1MB多。 我的网站流量非常精贵,所以此时使用webp的优势就体现出来了。我会把图片发送到我的电脑,然后使用电脑上的小程序打开进行格式转换。比如我的一个660KB的JPG图片,转换成webp格式后,只有115KB。 当然,如果你需要在手机上进行格式转换也可以,但是不要使用微信同步到电脑,因为它会进行格式转换,重新转为JPG。 推荐在电脑上使用电脑版的小程序直接进行图片格式转换,非常方便快捷。 实现:基于 Google 官方工具链 图片转换的实现原理与我之前的“音频转换”方案异曲同工,主打一个稳定与高效: 核心引擎:在服务端安装了 Google 官方出品的 webp 命令行工具链(cwebp)。 后端调度:依然由 Go 语言担任“指挥官”,接收小程序上传的 PNG/JPG 原图,调用外部 cwebp 进程进行压缩。 参数优化:在后端我预设了平衡性最好的质量参数,确保图片在压缩后的清晰度依然能够满足博客展示的需求。 闭环应用:现在我写每一篇博客前,都会先用小程序把配图过一遍,转成 Webp 后再上传。 成果:全站 Webp 化 目前,我的博客已经全面实现了图片 Webp 化。这不仅显著提升了网页的加载速度(SEO 评分都变高了),更重要的是,它帮我省下了实打实的流量费用。 ...
在“豆子工具”众多的功能里,音频转换(m4a 转 mp3) 是我使用频率最高、也最具有“个人救赎”色彩的一个。 起因:被软件更新“背刺”后的郁闷 这个功能的由来非常接地气:有一段时间,我需要频繁地将苹果手机录音产生的 m4a 格式文件转换成 mp3,因为当时某个必须使用的业务软件只认 mp3。 那时候我找遍了各种转换工具。最后发现某款主流音乐软件自带的转换功能挺好用。然而,好景不长,在一次软件自动更新后,这个功能竟然被砍掉了。我去搜老版本安装包,却发现根本找不到安全的下载路径。 那种“被绑架”的无奈感,相信每个工具控都深有体会。 进阶:大名鼎鼎的 ffmpeg 郁闷之后,我转向了技术人的终极方案——ffmpeg。 命令行虽然硬核,但确实强大到无以复加。一条简单的指令就能解决所有问题: ffmpeg -i input.m4a output.mp3 用了很长一段时间的命令行后,新的问题又来了:我总不能随时随地都带着电脑吧?如果我在外面,急需用手机转一个文件发给客户怎么办? 于是,我动了把 ffmpeg 搬进“豆子工具”的心思。 实现:极简架构下的“随时随地” 在小程序里实现这个功能,原理其实并不复杂,核心在于后端调度: 前端上传:小程序端选择 m4a 文件,上传至服务器。 后端处理:后端使用 Go 语言接收文件,通过 exec 模块调用服务器系统环境中的 ffmpeg 进程进行转换。 实时试听:为了保证体验,我在小程序里集成了一个音频播放器。转换前可以听一下是否选对了文件,转换后也可以即时试听确认效果。 即用即删:转换生成的文件在用户下载后会立即从服务器删除,既保护了隐私,也完全不占用宝贵的服务器存储空间。 感受:工具的本质是“自由” 自从这个功能上线后,我就彻底告别了 ffmpeg 命令行。 最爽的一点是随时随地:无论是在地铁上还是在户外,掏出手机,几秒钟就能完成格式转换。这种把强大工具揣在兜里的感觉,就是开发者最大的浪漫。 如果你也经常被各种音频格式限制折磨,或者对 Go 调用 ffmpeg 的具体代码实现感兴趣,欢迎在评论区交流。