实战:为 Hugo 博客开发一个公网 IP 探测 Shortcode
工具说明:在进行内网穿透(如调试 mole-go)或配置服务器白名单时,频繁查询公网 IP 是刚需。为了告别繁琐的登录和搜索,我开发了这个集成在博客中的实时探测组件。 🌐 公网 IP 探测 🌐 当前公网 IP: 正在探测... 复制 🛠️ 核心实现逻辑 这个工具基于 Hugo 的 Shortcode 功能实现,采用了异步加载技术,确保不会影响页面的首屏渲染速度。 ...
基于 Go + 小程序创建的“口袋指令中心”
我日常涉及 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"}, } 对外接口定义: ...
巧用Nginx重定向解决云存储文件地址变更的痛点
在移动应用分发、文件共享等场景中,我们常常会遇到这样的困境:云存储平台(如阿里云OSS、腾讯云COS、蓝奏云等)上传的文件地址一旦生成就无法修改,但客户端版本频繁迭代时,每次更新都需要重新生成下载链接和二维码。用户端需要不断更新访问入口,体验极差。我就碰到了此类问题,在上一篇文章,我介绍了自己的客户端,并分享了下载地址。但我发现当我需要重新升级版本时,已经生成的地址将无法变更。在我的文章中,我直接使用了文件下载地址。这就让我急需解决如何实现"一次分发,永久可用"的优雅方案?Nginx反向代理配合301重定向,正是解决这一痛点的利器。 一、问题根源:云存储的地址锁定机制 大多数云存储服务采用"对象存储"模式,文件上传后生成固定URL,该地址包含存储桶名称、地域、文件路径等不可变信息。这种设计虽然保证了数据一致性,却带来了分发难题:每次版本更新,开发者必须重新上传文件、生成新地址、制作新二维码,用户需要重新扫描或获取新链接。对于频繁迭代的应用,这种重复劳动不仅效率低下,更可能因用户未及时更新而影响使用体验。 二、解决方案:Nginx重定向的架构设计 核心思路是地址解耦——将"物理存储地址"与"用户访问入口"分离。通过Nginx服务器作为中间层,用户始终访问固定域名,Nginx根据配置将请求重定向到实际的云存储地址。当文件更新时,只需修改Nginx配置中的目标地址,用户端的访问入口保持不变。 具体架构如下: 用户 → 固定域名/短链接 → Nginx服务器(301重定向) → 云存储实际地址 这种设计实现了三个关键目标: 入口稳定性:用户扫描的二维码或保存的链接永久有效 维护灵活性:后台地址变更只需修改Nginx配置,无需重新分发 成本可控性:Nginx只做重定向,流量消耗极低,普通云服务器即可承载 三、技术实现:从配置到部署 环境准备购买一台云服务器(1核1G配置即可),安装Nginx,将自有域名解析到服务器IP。推荐申请SSL证书启用HTTPS。 Nginx配置示例 server { listen 80; server_name your-domain.com; # 方案一:直接重定向 location /download/app.apk { return 301 https://bucket.oss-cn-region.aliyuncs.com/v2.0/app.apk; } # 方案二:通配符匹配(更灵活) location ~ ^/app/(.*)$ { rewrite ^/app/(.*)$ https://new-bucket.oss-cn-region.aliyuncs.com/$1 permanent; } } 重定向类型选择 301永久重定向:搜索引擎会更新索引,客户端会缓存重定向结果,适合生产环境 302临时重定向:每次请求都会重定向,适合测试阶段频繁变更的场景 二维码生成 将固定地址(如https://your-domain.com/app/v2.0.apk)生成二维码,用户扫描即可下载。后续版本更新时,只需修改Nginx配置中的目标地址,二维码无需重新制作。 四、方案优势与注意事项 核心优势 零用户感知:用户无需关心后台地址变化 维护成本低:修改配置即可,无需重新上传二维码 扩展性强:可支持多版本共存、灰度发布等复杂场景 兼容性好:支持各种客户端(浏览器、APP、微信等) 实施建议 测试先行:在测试环境验证重定向逻辑,确保目标地址正确 监控告警:配置Nginx日志监控,及时发现重定向失败问题 备份机制:保留旧版本配置一段时间,避免新配置问题影响用户 性能优化:虽然重定向开销小,但高并发时需确保服务器性能 五、总结 Nginx重定向方案将复杂的地址管理问题转化为简单的配置变更,实现了"一次分发,永久可用"的理想状态。这种解耦思维不仅适用于文件分发场景,在API网关、微服务路由等场景中同样具有借鉴意义。对于中小型项目而言,这是成本最低、效果最直接的解决方案,值得每一位开发者掌握。 最后推荐一下我的豆子域名管家客户端,这个客户端可以解决域名证书到期忘记更换证书的问题。我是为了解决这个问题而想出来的这个方案。这是我的新的下载地址:https://lab.91demo.top/b011 这样当我修改下载地址时,我不用再变更这个地址,比如我最近刚刚优化了域名扫描逻辑,上传了新的版本,它生成了一个新的下载地址。 当然这个方案还是有一点瑕疵,它需要每次更新都登录服务器修改nginx配置文件,这对于非技术人员非常不方便。后期我还有再次进行优化,我将使用小程序完成新地址的更换。大致思路如下:开发一个轻量的Go服务,提供接口给小程序提交新的地址,然后保存编号和新地址到数据库,例如上面的b011是编号,它对应新的下载URL地址。然后使用Nginx代理这个服务,当用户访问b011时查询它的URL地址,然后返回301和新的地址。这样就不用每次都登录服务器修改Nginx配置,在手机上也方便操作,提供了极大的便利性,也可以交给非技术人员进行维护。
使用go生成DLL文件供第三方使用
我使用go写了一个http转WebSocket服务,这是一个命令行程序,双击可以直接运行,今天,有个新的需求,需要将这个命令行程序转为dll,然后供第三方使用。 1,改造程序 这个命令行程序很小,核心逻辑就是启动了一个HTTP服务,然后接收连接,然后通过WebSocket将内容转发出去。所以,在调整为dll时,仅仅需要导出两个函数即可。 1,StartServer,启动http服务,监听端口地址。因为不能阻塞,所以需要在监听服务时使用go方法启动一个携程。 2,StopServer,关闭http服务,需要提供给第三方,当它关闭时,需要调用它,释放监听地址等资源。 下面开始改造代码: package main import "C" // 必须导入 C 包 import ( // ... 原有导入 ... ) // 保持原有的全局变量和函数逻辑 (例如transDataGet, connWs 等) // 需要注意下面的//export这中间不能有空格,否则无法导出头文件 //export StartServer func StartServer() { // 将原本 main 函数里的逻辑放在这里 gin.SetMode(gin.ReleaseMode) r := gin.New() // ... 注册路由 ... r.Run("127.0.0.1:9988") } // 必须保留一个空的 main 函数 func main() {} // 其它参考StartServer,如果需要导出,一定要添加//export 2,编译命令 我是在windows环境,需要安装cgo环境,我安装了Mingw-w64支持C编译环境,执行以下命令: go build -buildmode=c-shared -o trans.dll main.go 执行后会生成trans.h和trans.dll两个文件。 3,验证dll 除了一些可以查看dll的工具外,还可以使用第三方语言进行测试。例如我这里使用Python。 import ctypes import time lib = ctypes.CDLL("./trans.dll") lib.StartServer() print("服务已在后台启动...") time.sleep(10) # 模拟第三方程序运行 lib.StopServer() print("服务已关闭") 4,再次优化代码 当实际测试的时候,我发现它会阻塞调用者,为了解决这个问题,我们需要再次改造程序。将启动服务改为非阻塞模式。将Gin的启动逻辑放入协程,并利用http.Server提供的Shutdown方法来实现优雅退出。 ...
告别域名过期焦虑,豆子域名管家支持批量检测加企微和钉钉通知
域名过期导致业务中断、流量缺失、品牌受损的案例比比皆是。手动记录域名的到期时间?是否会忘记,漏看? 我以前曾介绍过,我在微信小程序实现了域名证书监控功能。但是担心隐私,功能限制。这次我带来了豆子域名管家,本地化运行。 经过数月的规划和开发测试,豆子域名管家终于可以使用了。这是一款完全本地运行、支持批量导入管理以及可以企微和钉钉通知的域名证书检测工具。旨在解决域名过期监控难题。 特性 传统方式 豆子域名管家 运行方式 依赖云端服务 纯本地运行,数据不出本地 批量处理 手动逐个查询 一键导入,批量删除 通知渠道 单一(邮件/短信) 钉钉+企微双通道,支持Markdown格式 自定义提醒 固定时间提醒 可配置通知时间,提前预警天数 系统集成 无 系统托盘常驻,后台静默运行 隐私安全 数据上传第三方 域名数据和配置数据存本地 技术架构亮点: 工具基于Wails3框架构建,采用Vue3+NaiveUI前端技术栈,确保界面简洁美观,交互流畅,支持暗黑/浅色两种主题。 本地证书检测引擎,直接调用系统网络库进行TLS检测,无需依赖外部API。 多线程并发处理,使用go的特性批量进行域名检测。 跨平台兼容:支持Windows、macOS、Linux系统。 配置持久化,所有配置本地存储,重启后自动恢复。 支持域名证书检测,域名到期时间检测。 软件运行界面预览: 控制面板 配置页面 基本操作指南: 1,导入域名我们需要把要监控的域名按行录入到txt文档中,可以在软件配置界面下载示例模板,当准备完成后,选择刚才的文件,然后验证。没有问题后,点击确认导入即可。 2,配置机器人目前工具支持钉钉机器人和企业微信机器人,支持Markdown格式消息,可以查点击推送预览效果按钮查看推送效果。当输入机器人配置后,可以验证测试,当收到消息后说明配置成功,点击保存即可。可以同时配置企微和钉钉。这样会同时推送两份通知。 3,配置推送通知策略目前工具扫描调度间隔固定24小时,可以配置通知时间,和告警天数间隔。在通知时间,系统会将当天扫描的结果报表推送到机器人。如果用户更新某些域名证书后,可以在监控面板进行手动刷新。想查看效果,可以把通知时间设置为当前时间加几分钟,当到达时间后,将推送报表。确认无误后,可以调整为真正的推送时间。 4,系统托盘运行当完成域名导入和机器人以及通知策略配置后,可以关闭窗口,工具将自动缩放到系统托盘。如果需要退出,需要右键系统托盘退出。注意,如果退出工具,将不能监控域名,因为这是一个本地工具。所以需要工具长期运行。 5,监控面板监控面板的仪表板显示你的域名配置项统计信息,表格显示监视的域名列表。域名可以搜索,刷新以及删除。域名按照过期、告警、正常顺序排序。请查看最前面域名并及时处理。 工具按照自己的真实需求开发,如果你需要尝试,可以通过下方下载链接。目前仅提供了Windows版本。 https://lab.91demo.top/b011 如果您有任何问题和建议,欢迎反馈和交流。
拒绝频繁上传服务器!我用 Dufs + Mole-go 搭建了丝滑的内网穿透演示环境
最近开发完 Mole-go,想给它做个网站用来展示和下载。但我这个后端糙汉子,样式真搞不定,求助 AI 调了半天还是差点意思。最头疼的是,手机端调试得一遍遍输 IP,给朋友演示也得发一串 IP 端口,太不专业了!于是我一顿折腾,搞出了这套方案…… 为了解决这些痛点,我摸索出了一套“黄金组合”:Dufs + Mole-go + FRP + Caddy。这套方案打通了从本地到公网域名的全链路,实现了自动 HTTPS、域名访问以及极致的访问体验。 第一步:构建本地内容基石(Dufs) 一切的起点是本地文件服务。我选择使用 Dufs 作为静态服务器。它极其轻量,支持上传、搜索、打包下载甚至 WebDAV,是我演示 Web 应用或分发安装包的首选。 通过简单的命令,我在本地 5000 端口启动了服务。虽然此时它还被“困”在局域网内,但它为后续的展示提供了稳固的基础。 第二步:突破局域网束缚(FRP 与 Mole-go) 为了让公网流量能精准触达内网,我采用了经典的 FRP 方案,但在客户端层面,我使用了自己开发的 Mole-go。 服务端 (FRP Server):部署在具备公网 IP 的云服务器上,充当流量中转站。这个服务器配置可以很低,网站服务都在本地电脑,如果本地有数据库,也非常方便调试。 客户端 (Mole-go):这是我为 FRP 打造的桌面管理客户端。它封装了 frpc 核心,不仅提供了直观的 UI,还通过系统托盘设计彻底解决了“关闭窗口即断连”的痛点。 使用 Mole-go,我可以将本地 5000 端口通过加密隧道安全地映射到云端。它出色的资源管理和连接稳定性,确保了演示过程中即便网络波动,链接依然稳固如初。 第三步:优雅的网关入口(Caddy) 即便流量已到达公网,我也不希望朋友们通过 http://IP:端口 这种生硬的方式访问。我追求的是“域名+HTTPS”的专业感,这不仅是为了美观,更是为了开发环境需求,下次开发公众号等必须 HTTPS 环境时可以拿来就直接使用。 我选择了 Caddy 担任“守门人”。Caddy 的魅力在于其近乎零配置的 自动 HTTPS 功能。看中了它的简单方便,非常符合我的场景。在 Caddyfile 中,我只需写下: example.com { reverse_proxy localhost:7000 # 指向 FRP 映射出的本地端口 } 仅需这一行配置,Caddy 就会自动搞定 SSL 证书的申请与续签。当访问者输入域名时,映入眼帘的是受信任的绿色小锁头,所有的复杂端口逻辑都被完美隐藏。 ...
把项目做成像 frp 那样的多平台 Release
把项目做成像 frp 那样的多平台 Release Mole 项目已经开源,打算把仓库在 GitHub Release 页面中发布各个平台的安装包/二进制(像 frp 那样),已经完成脚本,可参考.github/workflows/release.yml,这个用来记录实现过程与遇到的坑,便于自己回顾。 大致流程 查阅 GitHub Actions、goreleaser、actions/create-release、actions/upload-release-asset 等资料。 在仓库中写一个 matrix workflow,在 Windows / macOS / Ubuntu runner 上分别构建并打包。 修复构建中出现的依赖与环境差异问题。 将构建产物上传为 Release asset(先查找/创建 release,再上传各平台包)。 调试并保证上传在 Release 页面能看到各平台包。 今天遇到并解决的主要问题(按流程顺序) Ubuntu 图形库版本不一致 问题:教程写的是 libwebkit2gtk 4.0,但在新版 Ubuntu runner 上只能安装 4.1。 处理:在 CI 的 apt 安装里兼容 4.0 和 4.1(尝试 4.1,或用 || 逻辑兼容两种包名)。 wails3 安装地址写错导致安装失败 问题:go install 用错了模块路径,安装一直失败。 处理:修正为官方地址(例如 github.com/wailsapp/wails/v3/cmd/wails3@latest),并确保 GOPATH/bin 在 PATH 中。 wails3 的 -platform / -o 参数在我的环境不可用 ...
音频格式转换新增支持 WAV
音频格式转换新增支持 WAV WAV 转 MP3 的 FFMPEG 命令: ffmpeg -i input.wav -codec:a libmp3lame -qscale:a 2 output.mp3 然后使用 go 封装一下。
Markdown 语法教程
Markdown 语法教程 我们使用 Markdown 作为我们内容的格式,所以学习 Markdown 就显得很必要了。 Markdown 是一种轻量级标记语言,后缀为.md。因我常用 Markdown 来写一些内容,记录下来常用语法格式。方便自己查找使用,也增加自己的一些流量。Markdown 可以用来撰写电子书,文章,博客等。介绍标题、段落的使用。 标题 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 ###### 六级标题 段落 Markd 段落没有特殊的格式,直接编写文件就好,段落的换行使用两个以上空格加上回车。也可以使用一个空行来表示重新开始一个段落。 字体 使用如下格式分别表示斜体,粗体,粗斜体。 *斜体文本* _斜体文本_ **粗体文本** __粗体文本__ ***粗斜体文本*** ___粗斜体文本___ 分割线 你可以在一行中用三个以上的星号、减号、底线来建立一个分割线,行内不能有其它东西。你也可以在星号或减号中间插入空格。 *** * * * ***** - - - --------- 删除线 如果段落上的文字要添加删除线,只需要在文字的两端加上两个波浪线~~即可。 ~~删除线~~ 下划线 下划线可以通过 HTML 的标签来实现: <u>下划线文本</u> 脚注 脚注是对文本的补充说明。 [^要注明的文本] 列表 支持有序列表和无序列表。 无序列表使用星号、加号、减号作为列表标记,这些标记后面要添加一个空格,然后再填写内容。 * 第一项 * 第二项 * 第三项 + 第一项 + 第二项 + 第三项 - 第一项 - 第二项 - 第三项 有序列表使用数字并加上.号来表示。 ...
Visit 项目维护Protobuf文件
Visit 项目维护 Protobuf 文件 豆子碎片小程序在版本 5.0 开始使用 Protobuf 传输和存储数据。在使用 Protobuf 前,使用的是 JSON 数据,原始 JSON 数据文件大小为 10KB,在生成 PB 文件后,PB 文件只有 4KB。本文章主要记录如何维护 Protobuf 数据,和开发中碰到的问题记录。 现在由于实际需求和维护原因,又切回使用 JSON 文件。 目前是使用 JSON 文件维护原数据,后期可以考虑使用数据库来存储。将 JSON 文件转为 PB 文件的工具是使用 Python 写的脚本。 下面开始一步一步介绍,直到 PB 文件可以使用。 一、首先定义 data.proto 文件,这个文件 Python 和 JavaScript 都需要用到。 syntax = "proto3"; message DataItem { string aid = 1; string name = 2; string category = 3; string label = 4; int32 grade = 5; } message DataList { repeated DataItem items = 1; } 上面的内容就是描述了一个数组对象。 ...