"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."
Resources
12Install
npx skillscat add mguozhen/flatkey-fleet Install via the SkillsCat registry.
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(claude、gpt),失败自动重试,不要让操作人重开:
bash $SKILL/scripts/authorize.sh --provider <claude|gpt>—— 本机浏览器自动弹
授权页并打印同一 URL。- 用
AskUserQuestion提示操作人(问题里不要带尖括号占位符):用这台 mac mini
对应的账号登录并授权,把页面整段 code 原样粘回来。 - 立刻运行
bash $SKILL/scripts/authorize.sh --provider <claude|gpt> --code "整段code"。 - 成功 → 换下一个 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)。