Files
TallyNote/docs/release.md
T
Qiufeng 4b9c80cc3a
TallyNote release / linux-x64 (push) Successful in 6m16s
feat: add safe one-click uninstall
2026-09-01 06:57:52 +08:00

6.2 KiB
Raw Blame History

Release、安装与更新

TallyNote 的发布包必须在目标 Linux 架构上构建。better-sqlite3、argon2、sharp 和 Node runtime 都包含原生代码,不能在 macOS 上交叉打包后冒充 Linux。

正式支持:Linux x86_64/amd64;脚本和安装器也支持在原生 runner 上提供 Linux aarch64/arm64(glibc 或 musl)。当前仓库 workflow 只生成 x64,arm64 必须使用对应 runner 单独构建发布。ARMv7/ARM32 只在你拥有对应 runner 和完整依赖构建结果时实验使用。Linux x86 32 位(i386、i686、ia32)明确不支持,Node.js 24 及原生依赖没有可维护的正式构建,因此安装器会拒绝它。

自动发布

向 Gitea 推送符合 SemVer 的 tag(例如 v1.1.2)会触发 .gitea/workflows/release.yml:

  1. 在 Linux runner 上安装依赖,执行 pnpm check、pnpm test 和 pnpm release:build。
  2. 由 scripts/publish-gitea-release.sh 计算所有归档的 SHA256SUMS。
  3. 如果提供 Ed25519 私钥则生成 SHA256SUMS.sig,通过 Gitea Releases API 创建/复用对应 Release,并幂等上传归档、清单和可选签名。

在仓库的 Actions secrets 配置:

  • GITEA_TOKEN:仅授予当前仓库 Release 写权限的 token。
  • TALLYNOTE_RELEASE_SIGNING_KEY:可选的 Ed25519 私钥 PEM。它只作为 CI secret 使用,绝不能提交到 Git。

也可以在 Linux 发布机上手动执行:

pnpm install --frozen-lockfile
pnpm check && pnpm test
pnpm release:build 1.1.2 ./release
GITHUB_REPOSITORY=awaioi/TallyNote \
GITEA_TOKEN=... \
  ./scripts/publish-gitea-release.sh v1.1.2 ./release

发布资产名称必须包含当前平台,例如 tallynote-1.1.2-linux-x64-glibc.tar.gz。同一个 Release 只保留一个 SHA256SUMS;有签名时再保留一个 SHA256SUMS.sig,签名覆盖清单完整原文。

curl 安装

安装器默认直接获取并安装 latest Release。它始终校验 SHA256SUMS 中的 SHA-256,不要求公钥或签名文件:

curl --proto '=https' --tlsv1.2 -fsSL https://git.awaioi.com/awaioi/TallyNote/raw/branch/main/install.sh | sudo bash

脚本会从 https://git.awaioi.com/awaioi/TallyNote/releases/download/v<版本>/ 下载当前架构归档和 SHA256SUMS,限制 HTTPS 重定向只能落在配置的受信主机,校验压缩/展开大小、条目数量、路径和特殊文件,再原子切换 /opt/tallynote/current。自定义仓库时同时设置 TALLYNOTE_REPOSITORY_URL、TALLYNOTE_RELEASE_API_URL 和 TALLYNOTE_RELEASE_ALLOWED_HOSTS;若使用独立 CDN,必须把 CDN 主机显式加入白名单。需要预览时显式加 --dry-run,需要固定版本时使用 --version。

如需启用签名校验,设置 TALLYNOTE_INSTALL_REQUIRE_SIGNATURE=true 并提供 --signing-key;后台更新同样可通过 TALLYNOTE_UPDATE_REQUIRE_SIGNATURE=true 和 TALLYNOTE_UPDATE_PUBLIC_KEY_FILE 开启。默认关闭签名要求,方便公开自维护仓库直接更新。

已有安装默认拒绝安装不高于当前版本的 release;只有在明确执行 --allow-downgrade(或设置 TALLYNOTE_ALLOW_DOWNGRADE=true)时才允许回退版本。

安装器拒绝预先存在的符号链接、非 root 拥有或对组/其他用户可写的安装、配置和备份目录。发布包同时携带 uninstall.sh,安装后会落到 /usr/local/sbin/tallynote-uninstall。--allow-unsigned 作为旧版本兼容参数保留。

安装布局:

/opt/tallynote/releases/<version>/   # 只读发布代码
/opt/tallynote/current -> releases/<version>
/opt/tallynote/.update-work/         # 0700 root:root,root 更新器临时工作区
/opt/tallynote/.update-state        # root 更新状态标记,异常中断后用于恢复
/var/lib/tallynote/                  # SQLite、附件、暂存和导出
/var/lib/tallynote-backups/          # 更新前数据备份
/etc/tallynote/tallynote.env

卸载与数据保留

默认卸载只移除发布代码、systemd 单元、更新辅助程序和已知配置,数据目录与更新备份不会删除:

sudo /usr/local/sbin/tallynote-uninstall

只有显式 --purge-data --yes 才会删除 SQLite、附件、暂存、导出、更新队列和备份;--purge-config 可在确认配置目录中没有其他文件后移除空配置目录。卸载器不会自动删除 tallynote 系统用户,也不会跟随符号链接删除目录。检测到 .update-state 或 update-request.json 时会拒绝执行,确认更新已经停止后使用 --force。

后台一键更新

将环境文件中的 TALLYNOTE_UPDATE_STRATEGY=systemd、TALLYNOTE_UPDATE_METADATA_URL 和 TALLYNOTE_UPDATE_ALLOWED_HOSTS 配好后,后台“系统更新”会读取 Gitea 的 /api/v1/repos/<owner>/<repo>/releases/latest。检查结果只显示当前平台匹配且通过 SHA-256 校验的资产;如果配置了 TALLYNOTE_UPDATE_PUBLIC_KEY_FILE 并启用签名要求,再额外验证 Ed25519 签名。

浏览器只能提交版本号和确认标志。Web 进程把受保护的任务文件交给 root 的 tallynote-update.path/tallynote-update.service,root runner 会重新读取配置源、重新下载并验证 metadata 和清单,不信任队列文件中的 URL 或摘要。更新前会备份数据,切换失败或健康检查失败会恢复旧版本;手动回滚:

sudo /usr/local/sbin/tallynote-update --rollback

更新检查和应用接口带有冷却时间(可用 TALLYNOTE_UPDATE_CHECK_COOLDOWN_SECONDS、TALLYNOTE_UPDATE_APPLY_COOLDOWN_SECONDS 调整),避免反复触发外部请求。服务单元默认仅监听 127.0.0.1,并使用最小化 systemd 权限;公网访问必须通过 HTTPS 反向代理,设置真实 TALLYNOTE_PUBLIC_ORIGIN、TALLYNOTE_COOKIE_SECURE=true 和明确的 TALLYNOTE_TRUST_PROXY 跳数。

更新任务详情按发起管理员隔离,任务错误只返回固定提示,不会把服务器路径、命令输出或上游响应泄露到浏览器;同一时刻仍只允许一个系统更新任务。

业务导出不是备份。停服后复制完整 /var/lib/tallynote 数据目录(含数据库、WAL/SHM、附件、暂存、导出和更新任务文件),并限制 SSH、备份和磁盘权限。拥有服务器文件权限的人仍可直接读取底层财务数据。