本文档记录本仓库“为高契合度候选自托管项目新增部署脚本(共享二进制应用扩展)”工作的目标、候选核实与实现快照;该阶段已完成并归档。 后续若要为共享
binary_app框架新增应用:资产映射以 §2 为准,硬性步骤见 §7,环境与验证注意见 §7/§9。 仓库整体持续进度以 Git 提交历史为准;docs/progress.log与docs/project-progress-and-remediation.md是本机工作日志,已不纳入 Git 跟踪,新 clone 中不会存在。
按优先级逐项修复深度审查清单(每项独立提交,均重建 dist 并通过 bash tools/verify.sh release):
- 发布包完整性(高):
lib/binary_app.sh新增bapp_verify_download,支持BA_SHA256(固定 64 位摘要)与BA_SHA256_ASSET_TEMPLATE(上游 sha256sum 格式校验文件,ARCH 感知、按主资产 URL 推导、fail-closed)。install/update 两条生命周期均在暂存前校验;未配置时保持旧行为,非空/最小尺寸/ELF 校验仍生效。guard:tools/checks/framework.sh#check_binary_app_download_integrity覆盖固定摘要、校验文件、摘要不匹配与未配置四条路径。 - 锁文件(高):
acquire_lock改为读写方式打开(9<>),不再截断锁文件中的注记;新增DEPLOY_LOCK_WAIT_SECONDS有界等待(默认仍为 fail-fast)。guard:check_acquire_lock_preserves_file_and_waits;tools/checks/backup.sh的结构性断言同步更新。 - 日志颜色(中):颜色仅在 stderr 为 TTY 时输出,
NO_COLOR/TERM=dumb仍全局关闭,新增DEPLOY_FORCE_COLOR=1供捕获场景强制开启。guard:check_logging_colors_are_tty_gated。 - GitHub 版本查询(中):
json_tag_name的grep -P探测按进程缓存,避免重复 fork;GITHUB_TOKEN改经 curl@file(/dev/fd 进程替换)传递,不再出现在/proc/*/cmdline。guard:check_github_release_tag_behavior增加令牌不进 argv 断言。 - self-update 下载诊断(中):
self_update_fetch_file与检查路径不再丢弃 curl stderr,失败原因(DNS/TLS/超时/max-filesize)会输出到 stderr 并进入 check-json 消息。 - cron 回退校验(中):非 systemd 回退新增
schedule_cron_expression_is_valid,按字段校验数值范围(分钟/小时/日/月/周 0-7)、拒绝畸形列表与反序范围;月/周英文名仍仅限 systemd OnCalendar。guard:check_schedule_cron_expression_validator。 - shellcheck 噪音(低):
impl/install_*.sh增加文件级# shellcheck disable=SC2034及原因注释,说明这些变量由 lib/app.sh 按名消费;verify 门的全局排除与理由保持不变。
有意不改(维持既有评估):operation.sh 的受控 eval(trap 恢复场景)、error() 在 $() 内只退出子 shell 的语义(已在 lib/logging.sh 加注释说明)、单应用交互命令的状态超时策略(依赖探针自身 curl --max-time)、端口冲突默认仅告警(README 已文档化 DEPLOY_FAIL_ON_PORT_CONFLICT)。
当前目标是在 Linux 开发环境中健壮地推进此前的审查清单。本机基线为 bash 5.2、Debian 包 Docker(经镜像拉取基础镜像)、shellcheck 0.11.0 和仅带 python3 的 PATH;python 兼容 shim 已在脚本与验证套件内解决。验证基线为仓库 tools/verify.sh,涉及 dist 的源码变更必须重建 generated release 并同 commit 提交。
- Python 可移植性:优先使用
python3,保留DEPLOY_PYTHON覆盖,验证套件在仅python3环境也可运行。 - i18n:注册缺失的
status.title,并为框架共享键增加一致性 guard。 - binary app 安装摘要:TLS 场景显示正确
https与托管 nginx 代理状态;中央deploy.sh的管理命令提示补上应用选择器,bundled/per-app 提示保持直接动作,并增加 shell 引用转义。 - TLS 失败回滚:清理 nginx 站点、默认站点备份与续签 cron;续签 cron 改为按应用命名;卸载仅在没有其他托管站点时删除旧全局 cron。新增 guard 覆盖失败安装、最终 nginx 校验失败和卸载清理。
- CPA stack release 资产解析:兼容 GitHub tag 带/不带
v前缀,修正 bashlocal同行赋值的展开顺序问题,并增加解析 guard。 - E2E 修复:CPA smoke 期望的配置路径从错误的
/etc/cpa_stack-deploy.conf修正为 APP_ID 对应的/etc/cpa-stack-deploy.conf;release fixture 增加 GitHub payload 所需的browser_download_url。 - 状态文档:补充
DEPLOY_STATUS_TIMEOUT_SECONDS、DEPLOY_STATUS_HEALTH_TIMEOUT_SECONDS、DEPLOY_STATUS_NO_PROBE、DEPLOY_STATUS_NO_NETWORK。 - 凭据 redaction:把 operation 摘要、operation 日志与通知共用的正则收敛到
operation_redact_text(),防止不同出口漂移。 - 文档引用:修正 PLAN 对未跟踪工作日志的引用,避免新 clone 后出现悬空路径。
bash tools/verify.sh all:通过。sudo bash tools/e2e-smoke.sh:五条场景全部通过(binary app、newapi、sub2api、pinned CPA stack、compose path)。- Docker 注意:当前网络不能直连 Docker Hub;可先拉取
docker.m.daocloud.io/library/debian:bookworm-slim后 retag 为debian:bookworm-slim。§9 的 Windows/Git-Bash 记录保留为历史背景。
__deploy_run_exit_handlers中的重复 handler 调用看似冗余,实际是用if __deploy_set_exit_status "$status"的条件上下文向 handler 传递退出码。简单合并分支会让非零状态触发set -e或丢失$?,保持现状更安全。lib/operation.sh中的eval属于 trap/restore 场景的受控构造,未引入外部不可信输入。
- 继续观察状态采集超时行为;当前设计只在
status-all聚合路径强制子 shell 超时,单应用交互命令依赖内部探针自身的curl --max-time。 - 关注并行 verify 中出现过一次的后备备份行为抖动;若再次出现,先定位
run_checks_parallel隔离性再调整测试。
在 E:\workspace\deploy-scripts 仓库中,为高契合度候选自托管服务新增与既有框架(apps/ + impl/ + bin/ + 顶层包装 + dist/ 生成 + verify 套件)完全一致的部署脚本:
- 单二进制 / GitHub Release 分发;systemd 服务托管。
- Debian / Ubuntu 全生命周期:install / update / backup / status / uninstall。
- 脚本内注释与 i18n 按仓库约定(i18n 中英双语、注释英文)。
用户指令(原文):“请你逐步的,按性价比实现这些项目的部署(高契合度候选那些),期间保持合适的提交粒度。期间你也可以查阅相关资料。如果某个项目不好弄,先跳过。现在开始吧!”
下表资产均经 GitHub Releases 网页
expanded_assets核实(API 限流 403,2026-08-18);下载 URL 形如https://github.com/<repo>/releases/download/<tag>/<asset>。本表是各impl/install_<app>.sh注释指向的权威资产映射。
| 项目 | repo | 最新 tag | 资产模式(安装包内二进制名) |
|---|---|---|---|
| ntfy | binwiederhier/ntfy | v2.27.0 | ntfy_2.27.0_linux_{amd64,arm64}.tar.gz(文件名版本去 v;二进制 ntfy) |
| meilisearch | meilisearch/meilisearch | v1.53.1 | 裸二进制 meilisearch-linux-amd64 / meilisearch-linux-aarch64(注意 aarch64 命名) |
| alist | AlistGo/alist | v3.63.0 | alist-linux-{amd64,arm64}.tar.gz(二进制 alist;不要用 musl 变体) |
| filebrowser | filebrowser/filebrowser | v2.63.23 | linux-{amd64,arm64}-filebrowser.tar.gz(二进制 filebrowser) |
| navidrome | navidrome/navidrome | v0.63.2 | navidrome_0.63.2_linux_{amd64,arm64}.tar.gz(版本去 v;二进制 navidrome) |
| frps | fatedier/frp | v0.71.0 | frp_0.71.0_linux_{amd64,arm64}.tar.gz(目录内 frps、frpc、frps.toml 示例) |
| gitea | go-gitea/gitea | v1.27.2 | 裸二进制 gitea-1.27.2-linux-{amd64,arm64}(去 v、无扩展名;另有 .xz 大体积资产) |
- 实现队列(按性价比排序,已全部完成):① ntfy → ② meilisearch / alist / filebrowser → ③ navidrome / frps / gitea → ④ gotify → ⑤ beszel。
- 已跳过:gatus —— GitHub release 无任何二进制资产(expanded_assets 为空),只适合源码构建/Docker。
- 暂缓(未纳入共享二进制队列,接入前需先补齐前置条件):
- miniflux:release 有裸二进制,但强制 PostgreSQL + 数据库初始化 + 首个管理员创建,需先设计数据库依赖 hook。
- AdGuard Home:发行包可用,但 DNS 53 端口 + Web UI 端口 + 首次 Web 配置向导超出当前单端口/单配置模型。
- syncthing:发行包可用,但配置生成、GUI 认证、同步目录与服务用户权限需专门安全策略。
- MinIO:Release 页面无稳定可映射 Linux 资产,需重新核实上游发布渠道。
- listmonk:候选仓库与发布渠道需重新核实,且有数据库依赖与初始化流程。
- 明确不做:Docker Compose 类应用(需框架级扩展)、PHP/DB 栈、重平台(GitLab/Grafana 等)、与 Nginx 反代定位冲突的反代工具。
共享生命周期库,复用仓库“共享 helper 优先于逐应用复制”的约定;细节以 lib/binary_app.sh 源码为准:
- 配置变量:
BA_ASSET_TEMPLATE(含ARCH占位)、BA_ARCHIVE_TYPE(none/tar.gz/zip)、BA_BIN_NAME、BA_MIN_SIZE、BA_HEALTH_URL/BA_HEALTH_CODES、BA_FIREWALL、BA_USE_ENV_FILE、BA_SERVICE_ARGS、BA_SERVICE_DESCRIPTION、BA_READWRITE_PATHS、BA_APT_PACKAGES、BA_ARCHIVE_PREFIX等。 - 应用 hook:
ba_asset_name、ba_download_urls、ba_write_config、ba_systemd_unit、bapp_health_probe(库调用、应用可覆盖)、ba_status_extra、ba_uninstall_extra、ba_validate_extra、ba_preflight_extra、ba_pre_start、ba_summary_extra。 - 生命周期核心全部以
bapp_*/ba_*前缀命名(bapp_install/update/backup/status/uninstall、binary_app_bootstrap等);impl/install_<app>.sh只写薄配置 + hook + 标准命令委托函数(每个含acquire_lock)。 - 关键硬化:路径默认值必须为 safe path 二级路径(如
/opt/<app>、/var/lib/<app>);配置仅经app_save_config写入;systemd 硬化默认NoNewPrivileges/PrivateTmp/ProtectSystem=strict/ReadWritePaths=${DATA_DIR} ${LOG_DIR}${BA_READWRITE_PATHS};二进制校验非空 +BA_MIN_SIZE(默认 1 MiB)+ ELF magic7f454c46;更新前自动备份、失败原子回滚;备份归档BACKUP_DIR/${APP_ID}_<label>_<ts>.tar.gz+BACKUP_KEEP_DAYS清理;i18n 全部走t+binary_app.*键(中英双语)。
2026-08-29 起
tools/checks/*.sh结构断言只检查源码(impl/、lib/、apps/),dist/仅由check_dist_is_up_to_date做“重建后与源码一致”比对; 此前“库函数命名避开检查正则子串、command systemctl计数避让”等约束已解除,无需再规避。
- newapi:已迁移(2026-08-29)。
impl/install_newapi.sh由 1074 行减至约 337 行,21 个专属 guard 精简为 4 个;框架新增BA_ARCHIVE_PREFIX="new-api"保持历史备份前缀兼容。 - vaultwarden / sub2api / cyberstrikeai:保留手写(已充分复用共享 helper:
app_binary_*二进制回滚、app_remove_*删除、app_save_config配置持久化、backup_restore_data_dir恢复、github_latest_release_tag版本查询):- vaultwarden:二进制经 Docker 镜像提取(非 GitHub Release)+ Web Vault 第二构件 + nginx 反代 + certbot TLS —— 迁移需框架新增“容器镜像提取”下载后端,收益/风险比低。
- sub2api:PostgreSQL/Redis 依赖 + 多构件备份(数据目录/配置目录/PG 转储)——备份格式与框架单目录打包模型不兼容。
- cyberstrikeai:源码构建(Go build + Python venv),不在二进制下载生命周期内。
9 个新增二进制应用全部实现并逐个提交(apps/impl/bin/wrapper/registry/checks + 重建 dist 同 commit),newapi 已并入共享框架;verify 套件(syntax/release/dispatch/guards)通过,e2e-smoke 接入 CI。
| 应用 | 端口 | 关键点 |
|---|---|---|
| ntfy | 2586 | /etc/ntfy/server.yml(serve 指定) |
| meilisearch | 7700 | 裸二进制 aarch64 命名;/etc/meilisearch.env(保留 master key) |
| alist | 5244 | server --data ${DATA_DIR};安装后提示 alist admin --data … 初始化管理员密码 |
| filebrowser | 8084 | FB_ROOT 默认 /srv/filebrowser |
| navidrome | 4533 | ND_* env;MUSIC_DIR 默认 /srv/music |
| frps | 7000 | /etc/frps/frps.toml + 随机 auth.token |
| gitea | 3000 | 裸二进制;BA_APT_PACKAGES="git";/etc/gitea/app.ini(sqlite) |
| gotify | 8085 | zip 发行包;/etc/gotify.env;首次生成并保留随机管理员密码 |
| beszel | 8090 | Hub tar.gz;数据目录 /var/lib/beszel;/api/health 健康检查 |
| newapi | 8080 | 已迁移至共享框架;BA_ARCHIVE_PREFIX="new-api" |
apps/<app>.sh:APP_ID/APP_NAME/i18n 注册/load_app_impl。impl/install_<app>.sh:薄配置 + hook + 标准命令委托函数(每个含acquire_lock)+binary_app_bootstrap。bin/install_<app>.sh:source core.sh + apps/.sh +main "$@"。- 顶层
install_<app>.sh包装:exec bash "${SCRIPT_DIR}/bin/<name>" "$@"。 lib/app_registry.sh的DEPLOY_APP_SPECS加一行(id|Name|apps/<id>.sh|impl/install_<id>.sh)。tools/checks/app-<app>.sh(check_* 函数)并注册到tools/verify.sh的 dispatch/guards 目标分支(check_target_groups_cover_all_checks强制每个 check 必须被某 target 调用)。tools/checks/dispatch.sh的check_app_localized_descriptions增加中英描述断言。dist/重新生成并与源码同 commit(verify 以DEPLOY_BUILD_COMMIT=verified SOURCE_DATE_EPOCH=0重建比对)。
自建 check 注意:app check 必须匹配共享库实现(如 command systemctl daemon-reload、bapp_health_probe),不要照抄既有应用的精确计数/函数名断言;
check_mutating_actions_acquire_locks 要求每个 do_install/do_update/do_backup/do_uninstall 函数体内有 acquire_lock;
i18n 一致性只校验 app.<prefix>.* 键(binary_app.* 在 lib 注册,不在该校验范围,但要保持无孤立键)。
& 'C:\Program Files\Git\bin\bash.exe' tools\verify.sh # 全量(含重建 dist,可能 3-6 分钟)
& 'C:\Program Files\Git\bin\bash.exe' tools\verify.sh syntax
& 'C:\Program Files\Git\bin\bash.exe' tools\verify.sh shellcheck # 约 40-60s
& 'C:\Program Files\Git\bin\bash.exe' tools\verify.sh release
& 'C:\Program Files\Git\bin\bash.exe' tools\verify.sh dispatch # 约 3-5 分钟
& 'C:\Program Files\Git\bin\bash.exe' tools\verify.sh guards # 约 2-3 分钟重建 dist:DEPLOY_BUILD_COMMIT=verified SOURCE_DATE_EPOCH=0 bash tools/build-release.sh all(Git Bash 中执行)。
- 本阶段(共享二进制扩展 + newapi 迁移)已完成归档;持续修复以 Git 提交历史为准,不要假设上述两个未跟踪日志在新 clone 中存在。
- 暂缓候选与“明确不做”项见 §2.2;若未来要接入需先补齐其前置条件(数据库 hook / 多端口模型 / 发布渠道核实等)。
- Windows PowerShell 会话;跑 bash 用
C:\Program Files\Git\bin\bash.exe(Git Bash 5.2.26)。 .gitattributes强制*.shLF,core.autocrlf=true;用 Pythonnewline=''/\n写文件避免 CRLF。- 不要用
bash -c 'cat > file <<EOF'的 heredoc 经 PowerShell 传参(引号被打乱);可靠写法:Python 显式\n写,或 PowerShell here-string +[System.IO.File]::WriteAllText。 - GitHub API 已限流(403):核实资产用网页
https://github.com/<repo>/releases/expanded_assets/<tag>。 - 不要在本机实装 install/update(需真实 systemd/root 服务环境且打 GitHub API);验证靠 verify 套件 + 语法/静态检查。2026-08-29 起真实安装矩阵由
tools/e2e-smoke.sh在 Docker 容器内执行(stub systemd + 文件版 curl shim,覆盖 binary_app 与 compose 两条路径;CI jobe2e-smoke每次 push 运行)。 - 二进制校验:非空、
BA_MIN_SIZE(默认 1 MiB)、ELF magic7f454c46;失败时删除临时文件并error。 - bash 语法问题排查套路:先
bash -n;函数级拆分逐个bash -n;注意行首}与后续 token 粘连、未闭合$(、heredoc 终止符、行末\续行。