mguozhen

flatkey-fleet

"Onboard and manage a global fleet of Mac mini nodes running the flatkey/sub2api gateway. A node self-onboards with one command (join Tailscale, deploy the sub2api stack, install the announce/dashboard/self-heal agents); the controller manages the fleet via a tracker and a HAProxy weighted load balancer. Triggers: flatkey fleet, onboard mac mini, deploy sub2api, add gateway node, fleet status, flatkey-fleet."

mguozhen 0 Updated 2w ago

Resources

12
GitHub

Install

npx skillscat add mguozhen/flatkey-fleet

Install via the SkillsCat registry.

SKILL.md

flatkey-fleet — 全球 Mac mini 节点舰队

100 节点终局架构。三层职责分离:

  • 网络层 Tailscale mesh —— 节点打 tag:flatkey-node,管可达与 NAT 穿透。
  • 调度层 NAS 上的 tracker(软状态注册表)+ 云主机上的 HAProxy 加权 LB
    (双活、主动健康检查)+ fleet-lbd(配置 daemon)。
  • 入口层 Cloudflare DNS/Tunnel —— 只做公网入口。

节点 = colima + 独立 postgres/redis/sub2api 栈,各自的 Claude/GPT 账号。
节点经常断电是常态 —— 每节点装 node-selfcheck 自愈,断电后无人值守自动恢复。

$SKILL 记为本 SKILL 所在目录。

模式分发

用户说 模式 在哪台机器跑
"上线这台机器 / onboard" onboard 被上线的 Mac mini 本机
"授权账号 / authorize" authorize 节点本机(OAuth 须本机 IP)
"看舰队 / list / status" status 中心控制机
"更新节点 / update" update 中心控制机
"签发月度 key / mint-key" mint-key 中心控制机

无参数时:若本机已是节点(存在 ~/flatkey-node/)则跑 status,否则问用户。


模式: onboard — 把【当前这台 Mac mini】上线为节点

终局是一条命令零接触。中心 mint-key 后,操作人在那台 Mac mini 上跑一次:

curl -fsSL https://flatkey.ai/fleet/<随机串>/bootstrap.sh | bash -s -- --office <城市>

操作人只填 --office。slug 自动生成(office 前缀 + 主机指纹);Tailscale 月度 key、
NAS registry、tracker 地址全烧进托管脚本。bootstrap 全自动:校验前置 → 接入
Tailscale → 装运行时 → 拉起 sub2api 栈 → 装 announce / dashboard / 自愈 三个定时器。

前置(无头节点必须 —— bootstrap 强校验,不达标直接失败)

  • 关闭 FileVault:否则断电重启停在磁盘解锁界面,无法无人值守恢复。
  • 开启自动登录:否则重启停在登录界面,用户级 LaunchAgent 全不跑。
  • 二者在 macOS 系统设置里各设一次即可。

skill 在 onboard 模式做什么

  • 本机已是节点(~/flatkey-node/ 存在)→ 直接跑 status 自检并报告。
  • 否则:把上面那条上线命令给操作人(完整 URL 在中心 mint-key 的输出里)。
  • 全程在节点本机、无 SSH。bootstrap.sh 会按需 sudo,需本机管理员权限。

模式: authorize — 给节点授权上游账号(与上线解耦)

节点 onboard 后默认 needs_auth、先上线后授权 —— 零接触上线不卡在 OAuth。
授权必须在节点本机做(OAuth 从本机 IP 发起,账号才绑这台机器的 IP)。

每个节点要授权两个上游账号:Claude 和 GPT。先查已有,只授权缺的:

docker exec flatkey-node-postgres psql -U sub2api -d sub2api -tAc \
  "select platform, count(*) from accounts group by platform"

anthropic 行 → Claude 已授权,跳过;有 openai 行 → GPT 已授权,跳过。

对每个还缺的 provider(claudegpt),失败自动重试,不要让操作人重开:

  1. bash $SKILL/scripts/authorize.sh --provider <claude|gpt> —— 本机浏览器自动弹
    授权页并打印同一 URL。
  2. AskUserQuestion 提示操作人(问题里不要带尖括号占位符):用这台 mac mini
    对应的账号登录并授权,把页面整段 code 原样粘回来。
  3. 立刻运行 bash $SKILL/scripts/authorize.sh --provider <claude|gpt> --code "整段code"
  4. 成功 → 换下一个 provider;失败(多半 code 过期)→ 回第 1 步重跑拿新 code;
    连续 3 次失败 → 把报错原文给操作人,停下等指示。

Claude 节点用 setup-token 而非标准 OAuth 时,claude 两条命令都加 --setup-token


模式: mint-key — 签发【月度】reusable 上线 key(中心控制机)

python3 $SKILL/scripts/fleet.py mint-key [--name 2026-05]

调 Tailscale API 签发一把 reusable、非 ephemeral、90 天、preauthorized 的 auth
key —— 当月所有新机共用。节点重连用持久化 node key,不再消耗 auth key。输出里有
要烧进托管 bootstrap.sh 的占位符值(__TS_AUTHKEY__ 等)与给操作人的上线命令。

托管:bootstrap.sh 挂在 flatkey.ai/fleet/<不可猜随机串>/bootstrap.sh —— URL 即
密钥;月度轮换 key 时连随机串一起换。

模式: list / status — 舰队看板(中心控制机)

python3 $SKILL/scripts/fleet.py list      # 查 tracker,渲染节点清单
python3 $SKILL/scripts/fleet.py status    # 清单 + 对在线节点 SSH 深检

模式: update — 更新节点(中心控制机)

python3 $SKILL/scripts/fleet.py update --name <slug>   # 单节点
python3 $SKILL/scripts/fleet.py update --all           # 全舰队滚动更新

经 Tailscale SSH 进节点 docker compose pull && up -d,按节点 sub2api_port 逐台
健康检查。


LB 控制面(部署在云主机,见 lb/)

lb/docker-compose.lb.yml 一组 = HAProxy + fleet-lbd + cloudflared,云主机起 2 份
做双活。fleet-lbd 每 15s 拉 tracker /peers,经 HAProxy Runtime API 热改加权
backend(零 reload)。健康摘除/回流归 HAProxy 主动健康检查(秒级)。详见 README.md

重要约束

  • Tailscale key / 节点密钥 / OAuth code 绝不写进会被提交的文件或日志。
  • 节点密钥在 ~/flatkey-node/.env(chmod 600),每台独立、不跨节点共享。
  • onboard 全程在节点本机;bootstrap.sh 会 sudo,需本机管理员权限。
  • 任何脚本非零退出都要如实把错误转述给用户,不要假装成功。
  • 中心模式需要 ~/.flatkey-fleet/config.yaml(见 README)。

Categories