一个程序包含两个模式:
server:动态创建任意数量的软件更新模块,管理各软件的当前版本、发布文件、更新说明和完整历史。client:检查指定软件的版本;版本不一致时下载任意类型的文件并原子替换目标文件。
只使用 Go 标准库,支持 Windows 和 Linux。客户端只下载文件,不会自动执行。
hot-updater.exe -mode server -listen 127.0.0.1:8080 -data-dir update-data -admin-user admin -admin-password "你的密码"浏览器打开:
http://127.0.0.1:8080/admin/
默认账号为 admin,服务端不内置默认密码。首次启动必须通过 -admin-password 或 UPDATE_ADMIN_PASSWORD 提供密码。管理端提供独立登录页、12 小时登录会话和退出登录。登录后可以修改密码;修改密码会立即注销所有旧会话,新密码以加盐哈希形式保存在 -data-dir/credentials.json,重启后仍然有效。
后台采用侧边栏分页布局:
/admin/ 概览
/admin/apps 软件管理
/admin/publish 发布更新
/admin/history 版本历史
/admin/logs 下载日志
/admin/settings 系统设置
首次启动时也可以通过参数或环境变量设置初始密码:
$env:UPDATE_ADMIN_PASSWORD="你的初始密码"
hot-updater.exe -mode server- 在“软件管理”中填写软件名称和唯一标识,例如名称
收银客户端、标识cashier。 - 在“发布更新”中选择目标软件,填写版本号和独立更新说明,再上传要交付的文件。
- 新发布会成为该软件的当前版本。之前的版本、说明和文件不会删除,会出现在该软件的历史记录中并可单独下载。
- 每个软件有独立接口,例如
GET /api/version/cashier和GET /download/cashier。
发布文件不限制后缀,可以上传 exe、txt、zip、7z、lrj 或无后缀文件。服务端保留原文件名,客户端按 -output 指定的路径保存并替换文件。软件标识只能使用小写字母、数字、- 和 _,并且必须以字母或数字开头。单个发布文件最大 512 MiB。
多软件目录和发布历史保存在 -data-dir/catalog.json。旧版 release.json 会在首次启动时自动导入为标识 default 的“默认软件”;原文件和旧更新包保持不变。旧接口 /api/version 与 /download/update 继续指向默认软件。
GET/POST /api/version/{软件标识} 获取当前版本、更新说明、更新时间和历史日志
GET /download/{软件标识} 下载该软件的当前更新文件
GET /download/{软件标识}/{版本记录 ID} 下载指定历史版本文件
GET/POST /api/version 获取默认软件版本(兼容旧客户端)
GET /download/update 下载默认软件当前文件(兼容旧客户端)
GET /health 健康检查
GET /api/version/cashier 返回示例:
{
"status": 1,
"app_id": "cashier",
"app_name": "收银客户端",
"version": "1.2.0",
"release_notes": "修复支付失败问题\n增加交班日志",
"download_url": "/download/cashier",
"direct_download_url": "http://updates.example.com/download/cashier",
"file_name": "cashier.exe",
"size": 171328,
"updated_at": "2026-08-20T01:02:03Z",
"history": [
{
"id": "1787190000000000000",
"version": "1.2.0",
"release_notes": "修复支付失败问题\n增加交班日志",
"file_name": "cashier.exe",
"size": 171328,
"updated_at": "2026-08-20T01:02:03Z",
"download_url": "/download/cashier/1787190000000000000",
"direct_download_url": "http://updates.example.com/download/cashier/1787190000000000000"
}
],
"data": {
"note_content": "1.2.0",
"version": "1.2.0",
"release_notes": "修复支付失败问题\n增加交班日志",
"updated_at": "2026-08-20T01:02:03Z",
"download_url": "/download/cashier",
"direct_download_url": "http://updates.example.com/download/cashier"
}
}history 按新到旧排列,包含当前版本和所有历史版本。direct_download_url 是服务器根据当前请求协议和 Host 生成的绝对直连,可以直接交给下载器;原来的相对 download_url 保留用于兼容旧客户端。data.note_content 保留为版本号,用于兼容原来的 WebNote 客户端格式。
后台中的“复制直连”按钮只复制绝对下载地址,不会打开地址或触发下载。可以把这个地址直接发给其他人,或交给浏览器、下载器和脚本使用;访问当前版本或任一历史版本的直连时,服务端才会写入下载日志。
所有软件的下载记录统一追加到 -data-dir/download-logs.jsonl。每条记录包含请求时间、来源 IP、软件名称和标识、版本号、当前/历史分类、文件名、HTTP 状态、成功或失败、发送字节数、文件总大小、耗时、User-Agent 和错误信息。后台 /admin/logs 支持按软件模块切换,按成功/失败筛选,并按 IP、版本、文件名、状态码等关键词查询。
日志最多保留最近 10,000 条,单次页面最多显示最近 500 条匹配记录。日志文件与 catalog.json 一起放在数据目录中,服务重启后继续保留。
如果需要让其他设备访问,将监听地址改为 :8080,并给服务器配置防火墙、HTTPS 和强密码。
当前 Windows 电脑的 WLAN 属于 Public 网络,Go 程序没有入站防火墙权限。项目中的 lan-proxy.js 使用系统已有的 Node.js 入站规则,把 0.0.0.0:18084 透明转发到管理端 127.0.0.1:18083。双击 启动管理端.cmd 可以同时启动两者:
电脑管理页面:http://127.0.0.1:18083/admin/login
默认软件接口:http://本机局域网IP:18084/api/version
指定软件接口:http://本机局域网IP:18084/api/version/cashier
如果以管理员身份运行 允许热更新端口.ps1 开放 TCP 18083,则也可以直接使用 Go 服务,不经过 Node 转发。
检查指定软件:
hot-updater.exe -mode client `
-version 1.0 `
-version-url http://127.0.0.1:8080/api/version/cashier `
-output "cashier.exe"管理端 API 会返回对应软件的下载地址,所以此时不需要填写 -download-url。客户端会显示远程版本、独立更新说明和更新时间。版本完全相同时不会下载;版本不一致时先下载到目标目录的临时文件,校验完成后再替换 -output。-output 可以是 exe、文本、压缩包、lrj 或其他任意目标文件。
客户端默认连接 http://127.0.0.1:8080/api/version。也兼容 WebNote 格式的版本接口和固定下载链接,但地址、笔记 ID 和下载地址必须显式提供:
hot-updater.exe -mode client `
-version 1.0 `
-version-url "https://你的版本服务/api" `
-note-id "你的笔记ID" `
-download-url "https://你的下载服务/update.bin" `
-output "update.bin"仓库提供 examples/懒人精灵/更新模块.lua。它会在脚本启动时检查版本,下载并校验 .lrj 更新包,安装成功后重启脚本;检查或安装失败时会记录日志并继续执行当前脚本。
公开文件不包含任何默认服务器。加载模块前配置 _G.LR_UPDATE_CONFIG:
_G.LR_UPDATE_CONFIG = {
serverBase = "https://你的更新服务器",
appID = "你的软件标识",
localVersionName = "1.0",
timeoutSeconds = 8
}
local loaded, loadError = pcall(require, "更新模块")
if loaded and type(checkScriptUpdate) == "function" then
pcall(checkScriptUpdate)
else
print("更新模块加载失败:" .. tostring(loadError))
endserverBase 不要包含末尾 /。版本接口使用 GET /api/version/{软件标识};更新包必须是 .lrj 文件。未配置服务器或更新失败不会阻止原脚本继续运行。
-mode client 或 server,默认 client
-version 客户端当前版本,默认 1.0
-version-url 指定软件的版本检查 API 地址
-download-url API 没返回下载地址时使用的固定下载地址
-output 客户端保存路径,默认 zf注册.lrj
-retries 版本检查重试次数,默认 3
-retry-delay 重试间隔,默认 1s
-timeout 单次 HTTP 请求超时,默认 30s
-listen 管理端监听地址,默认 127.0.0.1:8080
-data-dir 管理端数据目录,默认 update-data
-admin-user 管理员用户名,默认 admin
-admin-password 首次启动时的管理员密码,也可用 UPDATE_ADMIN_PASSWORD 设置
go test ./...
go vet ./...Windows x64:
$env:GOOS="windows"
$env:GOARCH="amd64"
go build -o dist/hot-updater-windows-amd64.exe .Linux x64:
$env:GOOS="linux"
$env:GOARCH="amd64"
go build -o dist/hot-updater-linux-amd64 .