返回博客

Tauri 2 内网 OTA 静默失败:不是必须 HTTPS,是你少了一个 flag

把桌面 APP 部署到无公网 TLS 证书的私有服务器时,Tauri 2 的自动更新器会在运行时静默报一个网络错误——URL 用浏览器直接访问完全正常,但 updater 就是拿不到 manifest。工程师通常会得出一个错误结论:"Tauri updater 必须 HTTPS,内网没法做 OTA",然后放弃,让用户手动重装。

这个结论是错的。

现象

内网私有部署场景:updater endpoint 是 http://192.168.x.x/update/update.json,浏览器访问返回正确的 JSON。但 APP 启动时 updater 回调的 error 是 network error 或 TLS handshake 相关报错(对着 80 端口尝试握手 443)。

构建日志也可能出现另一个迹象:.app.tar.gz.sig 文件根本没有生成——意味着签名密钥没有正确注入,updater 连签名都验不了,更谈不上拉包。

根因

Tauri 2 updater 插件默认拒绝 http:// scheme,会在发起请求前做协议校验,非 HTTPS 直接以 network error 返回,不走网络层。这和浏览器的混合内容策略类似,但报错信息不够明确,很容易被误判为服务器问题。

大多数教程和 v1 时代的文档都在强调「updater 需要 HTTPS 端点」,没有提到 v2 已经有官方 escape hatch。于是团队要么放弃 OTA,要么走弯路:

  1. 放弃 OTA,用户每次升级手动重下安装包。
  2. 给内网服务器签自签名证书 + 在每台员工机器上安装根 CA,折腾 Keychain / MDM / 杀毒软件信任——代价极高,而且对安全性毫无贡献,因为 updater 真正的安全锚点是 .sig 签名,不是 TLS。
  3. 在构建脚本里把 http: 强制替换成 https:,让 updater 对一个根本不存在的 443 端口静默失败——"内网 OTA 设计上不可用"写进了 ADR,未来的工程师继续踩同一个坑。
坑:TLS 不是 Tauri updater 的安全边界,.sig 才是

ed25519 minisign 签名验证是 updater 的真正安全锚点。攻击者即使在明文 HTTP 路径上篡改 .app.tar.gz,签名校验失败后 updater 拒绝安装。TLS 是额外防护层,不是必要条件。为了让 updater 能走 HTTP 而给所有员工机器推自签 CA,是用运维成本换了零安全收益。

正解

Tauri 2 提供了官方标志 dangerousInsecureTransportProtocol,专门用于内网/私有云/离线部署场景。三个字段必须同时存在:

{
  "bundle": {
    "createUpdaterArtifacts": true
  },
  "plugins": {
    "updater": {
      "endpoints": ["http://192.168.x.x/update/update.json"],
      "dangerousInsecureTransportProtocol": true,
      "pubkey": "<minisign 公钥完整内容,含头部注释,单行>"
    }
  }
}
  • createUpdaterArtifacts: true — 缺少此项,构建不会产出 .app.tar.gz.sig,updater 无文件可拉。
  • dangerousInsecureTransportProtocol: true — 官方 v2 标志,白名单 http:// scheme,不是社区 hack。
  • pubkey~/.tauri/<app>-updater.key.pub 的完整内容(含头部注释行),这是签名验证的锚点,不可省略。

capability 文件里也要加权限,否则 updater 调用被 ACL 拦截:

{
  "permissions": ["updater:default"]
}

构建时通过环境变量注入私钥(内容,不是路径):

export TAURI_SIGNING_PRIVATE_KEY="$(cat ~/.tauri/myapp-updater.key)"
export TAURI_SIGNING_PRIVATE_KEY_PASSWORD=""

构建完验证签名是否生成:

ls src-tauri/target/release/bundle/macos/
# 必须看到 YourApp.app.tar.gz.sig,没有说明私钥没注入成功
正解:dangerousInsecureTransportProtocol + createUpdaterArtifacts + pubkey 三件套缺一不可

flag 的名字里有 dangerous 是因为它放开了传输层加密,但签名校验始终开启——这是设计有意为之。没有 dangerousNoSignatureVerification 这种 flag,签名层无法绕过。

踩坑快速对照

| 症状 | 真实原因 | |------|----------| | updater 报 network error,浏览器访问 URL 正常 | 缺 dangerousInsecureTransportProtocol: true | | 构建产物没有 .sig 文件 | createUpdaterArtifacts: false 或私钥环境变量为空 | | updater 权限被拒 | capability 文件缺 updater:default | | ADR/注释写着"内网 OTA 不可用" | 基于错误前提,需要撤销并补充正确根因说明 |

一句话外卖

Tauri 2 updater 的安全边界是 ed25519 .sig,不是 TLS;内网 HTTP 端点加 dangerousInsecureTransportProtocol: true 即可开启 OTA,不需要给每台机器推自签 CA。