# Multi SimAdmin 一个用于聚合管理多个 [SimAdmin](https://github.com/3899/SimAdmin) 实例的轻量本地运维面板。 ## 功能 - 只需要在 `config.json` 配置多个 SimAdmin 地址。 - Animal Island / 动森风格 Dashboard:暖米色背景、棕色文字、Ribbon 飘带标题、NookPhone 应用格、胶囊按钮与波点卡片。 - UI 内直接新增、编辑、删除设备地址,配置实时写入本地 `config.json`,并提供返回首页入口。 - 实例舰队列表、状态筛选、搜索、当前设备摘要。 - 支持无密码实例状态读取;有密码实例可通过本地服务代登录并保持会话。 - 统一代理 SimAdmin API,内置 API 工作台,便于读取/调试设备、SIM、网络、短信、eSIM、OTA 等接口。 - 保留原始 SimAdmin 页面 iframe 嵌入;若目标站禁止 iframe,可一键在原站打开。 - 融合 [SimAdminHub](https://github.com/3899/SimAdminHub) 的管理思路:跨节点短信、通知、自动化与跨域健康自然融入 Fleet 节点总览体系,无需部署或接入外部 Hub。 - 敏感配置留在本地 `config.json`,仓库只提交 `config.example.json`。 ## 一键安装(macOS) ```bash curl -fsSL https://gitea.chickliu.fun/Hermes/multi-simadmin/raw/branch/main/scripts/install.sh | sh ``` 脚本会从 Gitea 下载源码,固定使用 pnpm `11.13.0` 安装依赖并构建 Web,然后启动: - LAN Gateway:`0.0.0.0:8788` - Control-plane API:`127.0.0.1:8790` - Canary Gateway:`8789` 保持关闭 安装完成后按终端输出访问 `http://<本机局域网 IP>:8788/fleet`。首次密码可在当前管理台直接设置。Gateway 默认监听所有网络接口,因此必须确保主机仅接入可信内网或已通过防火墙限制 8788 的来源;HTTP 部署不得直接暴露到公网,公网开放必须由前置代理提供 HTTPS 和访问控制。 > 当前生产秘密存储使用 macOS Keychain,因此一键安装脚本暂只支持 macOS。脚本不会覆盖已有源码目录或数据库,也不会占用已被其他进程监听的 8788/8790 端口。 ### 服务管理 下载脚本后可执行完整生命周期命令: ```bash curl -fsSL https://gitea.chickliu.fun/Hermes/multi-simadmin/raw/branch/main/scripts/install.sh -o /tmp/multi-simadmin-install.sh sh /tmp/multi-simadmin-install.sh status sh /tmp/multi-simadmin-install.sh restart sh /tmp/multi-simadmin-install.sh stop sh /tmp/multi-simadmin-install.sh start sh /tmp/multi-simadmin-install.sh uninstall ``` `uninstall` 默认只移除程序源码,保留数据库、Gateway token 和日志。默认安装位置为 `~/Library/Application Support/multi-simadmin`,可通过 `MULTI_SIMADMIN_HOME` 覆盖;额外 LAN Host 可通过 `MULTI_SIMADMIN_ALLOWED_HOSTS`(逗号分隔)配置。 ### Fleet 节点总览与跨域健康 `/fleet` 读取本机 Control Plane 中的节点状态、资源快照与设备号码,形成节点总览。侧栏在实例总数 / 在线 / 需处理之外,还聚合跨域健康指标: - 短信异常:标记哪些节点的短信接口不可用,点击直达 `/fleet/messages`。 - 通知异常:汇总跨节点通知队列的 pending + failed 数量,点击直达 `/fleet/notifications`。 节点卡片直接进入对应实例详情,查看 CPU、内存、温度、SIM 号码、平台与版本。 ### 跨节点短信中心 `/fleet/messages` 融合官方 SimAdminHub 的短信中心形态:它通过本地 Control Plane 按节点读取 SimAdmin 的 `/api/sms/list`,再跨设备聚合搜索、展示与发送。 - 跨设备记录:汇总各节点最新短信,支持按号码、内容或节点名称搜索,并分页加载。 - 会话视图:按号码分组为会话,节点栏 / 会话栏 / 消息栏三栏工作流,默认打开最新会话。 - 发送短信:从可用节点下拉选择目标设备,提交到 `/api/v1/fleet/messages/send` 后由 Control Plane 转发到对应 SimAdmin。 - 批量删除:可在短信记录中勾选选择并确认删除,Control Plane 通过严格白名单的 `/api/sms/batch-delete` 按节点批量清理,未成功项会以逐条失败原因返回。 - 安全边界:短信正文与号码只在本地页面展示;批量删除请求最多 500 条,且不接收外部 Hub 地址、Webhook 或任何可注入字段。 ### 跨节点通知中心 `/fleet/notifications` 融合官方 SimAdminHub 的通知中心能力:它按本地节点聚合阅读 SimAdmin 的通知接口,再跨设备汇总转发通道、转发规则、转发日志与失败重试队列。 - 设备可用性:自动登录后读取 `/api/notifications/config`、`/api/notifications/logs` 与 `/api/notifications/queue`,无法读取的实例单独标记。 - 转发通道:统计通道总数、启用数以及常见的 webhook、Bark、PushPlus、企业微信、钉钉、飞书、Telegram、邮件等类型。 - 转发日志:展示成功、失败、免打扰、未匹配、无可用通道与最近记录。 - 失败重试:展示待发送、定时、重试中、发送中和失败的队列摘要,并支持整队列重试、单条重试或删除积压项。 - 安全边界:只返回经过白名单清洗的计数与最近条目,不暴露通知原文、webhook/token/secret 或模板配置。 ## 旧版开发入口 旧 `server/` 与 `public/` 仅用于历史兼容和开发验证,不是当前生产安装入口: ```bash cp config.example.json config.json npm install npm start ``` ## 配置 编辑 `config.json`: ```json { "server": { "host": "127.0.0.1", "port": 8788 }, "instances": [ { "id": "simadmin-open", "name": "无密码 SimAdmin", "url": "http://192.168.68.1:3000", "description": "密码保护关闭或尚未配置密码的实例", "auth": { "mode": "none" }, "tags": ["open"] }, { "id": "simadmin-password", "name": "有密码 SimAdmin", "url": "http://192.168.68.2:3000", "description": "服务端代登录并保存会话 Cookie;密码只保存在本地 config.json", "auth": { "mode": "password", "password": "CHANGE_ME" }, "tags": ["password"] } ] } ``` 字段说明: - `id`:唯一标识,只能包含字母、数字、下划线、短横线、点号。 - `name`:页面显示名称。 - `url`:SimAdmin 原始访问地址。 - `description`:可选描述。 - `auth.mode`:`none` 表示无密码;`password` 表示由本地聚合服务代登录。 - `auth.password`:可选。本地保存后可自动刷新会话;不要提交真实密码。 ### 为什么只接受 IP 地址? 聚合服务会代理设备管理 API。为避免 DNS 重绑定将已校验主机名切换到本机或元数据地址,设备 URL 必须使用明确的 IPv4/IPv6 字面地址;局域网 IP(如 `192.168.x.x`)可正常使用。 ## 常用命令 ```bash npm test npm start ``` ## 架构与阶段边界 第一阶段采用无构建链的可组合架构: - `server/index.js` 是唯一 bootstrap,负责路径、监听和优雅关闭;`server/app.js` 的 `buildApp()` 无导入副作用,可通过 Fastify `inject()` 测试。 - `server/config/` 提供 immutable snapshot、串行事务和 temp + atomic rename;模板只用于首次加载,提交始终写实际 `config.json`。 - `server/clients/` 在配置成功提交后 reconcile;`server/status/` 与 `server/proxy/` 是独立边界。 - `public/domain`、`infrastructure`、`state`、`router` 放置 Node 可测试模块,`app.js` 暂作 DOM composition/controller。 - `styles.css` 依次导入 tokens、base、components、responsive。 验证命令: ```bash npm test find server public test -name '*.js' -exec node --check {} \; npm audit --omit=dev --audit-level=high git diff --check ``` 第二阶段安全加固后,服务仅允许监听 loopback;显式配置 `0.0.0.0`、LAN 地址或非 loopback 主机将拒绝启动。实例目标必须为允许的 IP 字面地址,拒绝凭据、loopback、unspecified、link-local、metadata、multicast 及主机名,以避免 DNS 重绑定。生产代理使用精确路径/方法白名单,写操作要求短期一次性确认令牌。 ## 注意 - 当前项目是本地管理面板,不修改 SimAdmin 本体。 - `config.json` 可能包含真实设备地址和密码,已在 `.gitignore` 中排除。 - 部分写操作接口(短信发送、网络模式、频段/小区锁定等)会改变设备状态,执行前请确认目标实例。