@hyydev/myops
v0.2.0
Published
Open source server control panel: manage a fleet of Linux and macOS machines over SSH from one dashboard
Maintainers
Readme
English · Tiếng Việt · 中文 · 한국어 · 日本語
面向自有 Linux 与 macOS 服务器的自托管控制面板:实时指标、nginx 站点、pm2 应用、Docker、数据库、 cron、防火墙、备份、SFTP 文件浏览器和完整的 SSH 终端 —— 全部在浏览器里完成,只依赖 SSH。
Next.js 16(App Router)嵌入自定义 Hono 服务,数据经 Prisma 存入 SQLite。
与众不同之处
- 只用 SSH。 没有守护进程回连,不用额外开端口,不需要云账号。是 myOps 主动连出去,运行 myOps 的机器本身不需要公网地址。
- 无二进制依赖的采集脚本。 可选的指标 agent 就是一个 POSIX shell 脚本 —— 目标机器上不用装任何 运行时。
- 从不探测系统类型。 每条与系统相关的命令都写成 POSIX
if/elif分支后交给目标机器执行,所以同 一份代码在 Debian、RHEL、Arch、Alpine、SUSE 和 macOS 上都能跑。 - 界面文字不来自服务端。 API 只返回消息键,由界面负责翻译,因此每个页面都同时存在越南语、英语、 中文、韩语和日语版本。
界面截图
| | | | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | 总览 —— 实时 CPU/内存/磁盘/网络、经 SSH 探测的服务栈、最近操作记录 | 应用 —— 通过 nvm 管理的 Node.js 版本与全部 pm2 进程,深色主题 | | Runner —— 在服务器上安装并注册 GitHub Actions 与 GitLab CI runner | 设置 —— 主密码、SMTP 与 Telegram、Web 推送、加密的配置备份 |
功能
| 模块 | 你能得到什么 |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| 服务器 | 整个机群的卡片视图,含状态、CPU/内存/磁盘和标签筛选;用密码或 SSH 密钥(支持 passphrase)新增、编辑、删除服务器,保存前先测连接 |
| 总览 | 系统信息、实时图表、服务栈状态、待更新的软件包、swap 管理、重启、临时命令、最近操作 |
| 指标 | agent 在目标机器上每 15 秒采样一次,myOps 每 30 秒经 SSH 拉取;CPU/内存/网络/负载图表跨度 1 小时至 7 天 |
| 站点(nginx) | 创建反向代理、静态和跳转 vhost,直接编辑原始配置,启用/停用,配置测试与 reload,签发/续期 Let's Encrypt 或导入自有证书 |
| 应用(pm2) | 从 Git 仓库部署,start/stop/restart/reload,调整实例数,保存与恢复进程列表,按应用实时看日志,安装 pm2 及其开机自启单元 |
| Docker | 容器的操作与详情、镜像的更新检查与拉取、卷、网络、磁盘占用、prune,以及带内联编辑器和日志的 Compose 栈 |
| 数据库 | MySQL/MariaDB、PostgreSQL、MongoDB 与 Redis,原生安装或容器化皆可;建库、删库、导出、清空 Redis、安装与卸载引擎 |
| Cron | 按用户列出、创建、编辑、启停、立即运行和删除任务,附人类可读的调度说明与单任务日志 |
| 防火墙 | ufw 或 firewalld 规则、服务控制、fail2ban jail 与解封,以及自动生成的加固建议 |
| 用户 | 系统账号、用户组、home 与 shell、重置密码、每个用户的授权 SSH 公钥 |
| Runner | 把 GitHub Actions 与 GitLab CI runner 注册成服务并加以控制 |
| 备份 | restic 仓库配置、定时与手动执行、可选先导出数据库、浏览快照、恢复、导出与 forget |
| 可用性监控 | 从 myOps 主机发起的 HTTP/TCP 探测:状态码、正文匹配、响应时间、24 小时可用率与 TLS 到期;宕机和恢复时都会通知 |
| 文件 | 浏览、查看和编辑文本文件,拖拽上传、下载、重命名、chmod、删除 —— 全部走 SFTP |
| 终端 | 基于 WebSocket + xterm.js 的真实 SSH shell,自动适配尺寸,切换路由时标签页保持存活,带会话数量上限与空闲超时 |
| 日志 | 发现日志源(journald 或普通文件),经 WebSocket 实时跟踪,按级别与关键词过滤,可下载 |
| 端口 | 监听端口与 CPU 占用最高的进程,按 PID 结束进程(myOps 拒绝杀掉自己的 SSH 会话) |
| 磁盘 | 文件系统的使用率与 inode、块设备、用 du 找出目录里到底是什么占了空间、一键清理缓存与轮转日志,以及给空闲磁盘分区+格式化+挂载 |
| 机群批量 | 按标签或手动挑选服务器,对它们执行同一个动作(自定义命令、系统更新、重启、nginx/pm2 reload、Docker prune、备份),每台一份日志 |
| 维护窗口 | 为单台服务器或整个机群设定静默时段,期间屏蔽全部通知 |
| 告警 | 按指标设定阈值规则,通过邮件(SMTP)、Telegram 和 Web 推送送达,每次越界只触发一次 |
| 设置 | 主密码、带测试按钮的 SMTP 与 Telegram 凭据、推送通知、查看并复制主密钥与 MCP token、整份配置的加密导出/导入 |
| MCP | /mcp 上的 Model Context Protocol 端点:AI 助手可查看全机群的指标、子系统状态与日志,并执行重启、备份、更新和部署;token 首次运行时自动生成 |
| 安全 | 单一主密码(argon2id)、httpOnly 会话 cookie、SSH 凭据用 AES-256-GCM 加密、所有改动状态的操作都写审计日志 |
| 其他 | 可安装为 PWA 并支持 Web 推送、Cmd/Ctrl + K 命令面板可跳到任意服务器与页面、明暗主题、五种语言 |
架构
Browser ──http──► Hono ──► /api/* REST
└──ws────► ──► /ws/terminal ⇄ SSH shell
├─► /ws/agent-install agent install log
├─► /ws/app-logs live log stream
└─► everything else → Next.js
MCP client ──http──► Hono ──► /mcp read + operate tools (bearer token, generated on first run)
myOps ──ssh──► target: myops-agent (systemd timer / cron)
└─ writes /var/lib/myops-agent/metrics.jsonl (ring buffer)agent 从不主动外连 —— 是 myOps 通过 SSH 进去读文件,所以 myOps 主机不需要公网地址,目标机器除 SSH 外不用开任何端口。myOps 停机期间 agent 照常采样;下次拉取会从记录的游标继续,图表因此不会断档。
| 路径 | 职责 |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| server.ts | 自定义服务:Hono 先接请求,截走 /ws/* 的 upgrade,其余(含 HMR)转给 Next;同时启动调度器 |
| src/server/api.ts | 挂在 /api basePath 的 Hono 应用、会话中间件、集中式错误处理、Server-Timing |
| src/server/routes/ | 只负责 HTTP 与 WebSocket:auth、servers、settings、metrics、fleet、ops、files、terminal、agent、log-tail、mcp |
| src/server/services/ | 所有会碰到目标机器的命令:ssh、shell、platform、jobs、cache、crypto,以及每个领域一个 service |
| src/server/mcp/ | 建立在 service 之上的 MCP 工具面 —— tools.ts 只读、actions.ts 写,只要 MYOPS_MCP_TOKEN 有值就在 /mcp 提供服务 |
| agent/myops-agent.sh | POSIX shell 编写的 agent,目标机器无需任何运行时 |
| prisma/schema.prisma | Setting、Session、Server、Credential、MetricSample、Job、AuditLog、SslCert、UptimeCheck、UptimeSample、Maintenance、BackupConfig、NotifyRule、PushSubscription |
| src/app/(app)/ | 需要登录的路由组:机群面板、单机各页面、批量执行、维护窗口、全局设置 |
| src/components/ui/ | 设计系统 —— 一个文件一个组件,由 index.ts 统一再导出 |
| messages/ | vi/en/zh/ko/ja.json,键集完全一致,按页面分 namespace |
分层规则:route 里不写任何 SSH 逻辑,客户端除类型外绝不 import service。
快速开始
不用克隆仓库,最快的试用方式:
npx @hyydev/myops # http://localhost:3000全局安装(npm i -g @hyydev/myops)会把更短的 myops 命令放进 PATH。
状态文件放在 ~/.myops —— 含主密钥的 .env 与 SQLite 文件 —— 所以升级不会丢。PORT 与 HOSTNAME
可覆盖默认值,其余选项见 myops --help。
从源码运行,用于开发或长期部署:
git clone <repo> myops && cd myops
yarn install
yarn dev # http://localhost:3000配置到此为止。yarn dev 和 yarn start 都会从 .env.example 生成 .env、在缺失时生成
MYOPS_MASTER_KEY,并在服务启动前应用迁移(见 数据库)。已存在的密钥永远不会被重新生成
—— 换一把新的会让所有已存凭据无法解密。
请备份这把密钥。 myOps 保存的每一份 SSH 凭据都用它加密,且没有任何找回途径。副本请放在
prisma/dev.db 以外的地方。
首次运行时 myOps 会跳转到 /setup 设置主密码。之后:添加服务器 → 测试连接 → 安装 agent。
环境要求
- myOps 主机上装有 Node.js 20 或更高版本
- 能 SSH 到每台目标机器,目标机器有 POSIX shell,且改动状态的操作可用
sudo/root
myOps 执行的是非交互式命令,因此使用 sudo -n:SSH 账号必须要么是 root,要么拥有免密 sudo。
大多数 Linux VPS 本来就是 root,无需额外配置。macOS 上则必须自行配置,因为默认禁止 root 登录
SSH,而管理员账号仍会被要求输入密码:
# 在目标 macOS 机器上执行
sudo visudo -f /etc/sudoers.d/myops # 加入:<user> ALL=(ALL) NOPASSWD: ALL
sudo systemsetup -setremotelogin on # 若远程登录未开启则打开实在无法使用免密 sudo 时,myOps 也可以代为输入密码。用密码登录的账号会自动复用该密码;用密钥登录
的账号可以在服务器表单里填 sudo 密码。无论哪种方式,这个密码都和其他凭据一样被加密、绝不由 API
返回,并通过 stdin 喂给 sudo -S,所以它不会出现在命令行或 sudo 日志里。
myOps 不会盲目下手:测试连接会如实报告该账号究竟能做什么 —— root、免密 sudo、需要密码的 sudo,
还是完全没有 sudo —— 只有确实会提示输入密码的机器才会退回 sudo -S。
支持的系统
所有开启 SSH 的 Linux 发行版,外加 macOS。myOps 不会预先判断系统类型:每条与系统相关的命令都在
src/server/services/platform.ts 里写成 POSIX if/elif 分支,由目
标机器在一次往返内自行选择分支。
| 层面 | 支持范围 |
| --------- | ----------------------------------------------------------------------- |
| 包管理器 | apt-get、dnf、yum、zypper、pacman、apk、Homebrew |
| init 系统 | systemd、OpenRC、launchd(经 brew services)、sysvinit |
| 防火墙 | ufw(Debian、Arch)、firewalld(RHEL、SUSE)、应用防火墙(macOS) |
| Cron | cron、crond、cronie、busybox crond |
| 系统日志 | journald,或无 systemd 时的 /var/log/syslog · /var/log/messages |
| 机器指标 | Linux 上读 /proc;macOS 上用 sysctl + vm_stat + netstat + top |
| CPU 架构 | x86_64 与 aarch64/arm64(含 Apple Silicon) |
有几处限制来自上游,而非 myOps 本身:
- MongoDB 官方仓库只提供 deb 与 rpm;在 Arch 和 Alpine 上请用 Docker 模式。
- GitHub Actions runner 会把自己注册成 systemd 服务,因此该按钮只在 systemd 机器上有效。
- 用户页面依赖
shadow工具链(useradd、usermod、chpasswd);Alpine 需要额外装shadow包,macOS 用的是dscl,所以该页面暂时不可用。 - Nginx:只有 Debian 默认带
sites-enabled。创建站点时,若nginx.conf里没有对应的include行,myOps 会往conf.d里补一条,因此 vhost 在各发行版都能生效。macOS 上 Homebrew 把 vhost 放在$(brew --prefix)/etc/nginx/servers;myOps 能统计到它们,但站点页面写入时仍按 Linux 的目录 结构。 - macOS 上的防火墙、备份与证书目前只读:操作按钮说的仍然是 ufw/firewalld 与 certbot。
有三个页面只支持 Linux —— 防火墙、用户和 CI/CD runner —— 当服务器报告的是别的系统 (macOS、BSD、Windows)时,侧边栏对应入口会变灰失效,命令面板里也不再出现,手动输入 URL 则会落到一 个解释原因的页面。若 agent 尚未报告系统类型,所有页面都保留:myOps 绝不靠猜测隐藏功能。
Agent
在界面里安装(总览页 → 安装 / 更新 agent)。myOps 会:
- 经 SFTP 把
agent/myops-agent.sh复制到/usr/local/bin/myops-agent。 - 创建
myops-agent.service与.timer并systemctl enable --now(周期 15 秒)。 - 目标机器没有 systemd 时,退回到每分钟跑四次的 cron。
- 把登录用户记进
/var/lib/myops-agent/owner(root 所有,0644)。agent 由 timer 或 cron 以 root 身份运行,此时SUDO_USER为空,没有这个文件就找不到装在登录用户家目录里的 nvm、Homebrew 或 Docker Desktop 可执行文件。
agent 只读取 /proc/stat、/proc/meminfo、/proc/net/dev、/proc/loadavg、/proc/uptime 和
df -P /(macOS 分支用 sysctl、vm_stat、netstat -ib 和 top),然后追加进一个 2000 行的环形
缓冲(约 400KB)并自行截断。卸载只需点一个按钮。
没装 agent 的服务器仍会通过每轮一条 SSH 命令上报内存/磁盘/负载;只有 CPU% 会是空的,因为它需要连续 两次采样。
MCP 服务
myOps 可以通过 Model Context Protocol 把机群暴露给 AI 助手,让模 型直接看到真实运行状况,而不是听别人转述 —— 顺手把小问题修掉,不必由人来传话。
大部分工具只读。其中十个能操作机群,且能做的事是刻意收窄的:重启应用、容器、compose 栈和服务,启停
站点与 cron 任务,执行备份,签发证书,安装更新和部署。没有任何工具能删除站点、应用、容器、数据库
或用户,不能重启机器,也没有执行任意命令的工具。 每次操作都写审计日志,可能中断服务的那些还带
destructiveHint 标记,客户端可据此先向人确认。
token 和主密钥一样在首次运行时自动生成,写入 .env 的 MYOPS_MCP_TOKEN。你不需要手工产出:首页的
连接 MCP 会直接给出填好 token 的客户端配置和 CLI 命令,设置 → 密钥里可以看到原始值。
要关掉这个端点,把值清空后重启。myOps 只在 .env 里完全没有这一行时才生成 token,所以留空会被视为
明确的关闭意图,永远不会被自动填回。长度不足 24 个字符会打印警告,并让 /mcp 返回 404。
把客户端指向 http://localhost:3000/mcp,带上 Authorization: Bearer <token>。Claude Code 的写法:
claude mcp add --transport http myops http://localhost:3000/mcp \
--header "Authorization: Bearer $MYOPS_MCP_TOKEN"| 工具 | 回答什么 |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| list_servers | 整个机群及其最新的 CPU/内存/磁盘采样。从这里开始 —— 它返回其他工具都要用的 serverId |
| server_detail | 连接信息、硬件、系统、已装服务栈,以及各板块的计数 |
| server_metrics | 1 小时至 7 天的 CPU/内存/swap/磁盘/负载/网络序列,读自 myOps 数据库 |
| server_state | 经 SSH 实时探测的某个子系统:nginx、apps、docker、databases、firewall、cron、node、ports、disk、runners、users、backup、swap、sshKeys |
| check_updates | 待更新的系统软件包、其中多少是安全更新、过期的服务栈组件,以及是否需要重启 |
| monitoring | 可用性检查及其最近结果与 TLS 到期时间、告警规则及是否正在触发、生效中的维护窗口 |
| uptime_history | 某个可用性检查已记录的探测结果:通/断、响应时间、状态码 |
| log_sources / read_logs | 先看有哪些日志可跟踪,再按级别、关键词和时间窗口去读 |
| app_logs / container_logs | 某个 pm2 应用或某个 docker 容器的日志尾部 |
| list_files | 经 SFTP 列一个目录 —— 名称、大小、权限、mtime。文件内容是刻意不暴露的 |
| list_jobs / recent_activity | 后台任务及其输出,以及所有改动状态操作的审计记录 |
| fleet_overview | 机群整体:在用的标签,以及最近一次跨多台服务器执行的动作 |
会改动状态的工具:
| 工具 | 做什么 |
| --------------------------------- | ------------------------------------------------------------------------------------ |
| app_action / container_action | pm2 应用的 start、stop、restart、reload;容器的 start、stop、restart、pause、unpause |
| stack_action | docker compose 栈的 up、start、stop、restart 或 pull |
| site_action / nginx_action | 启用或停用某个 vhost;测试、reload 或重启 nginx |
| cron_action | 启用、停用或立即运行某个 cron 任务 |
| run_backup | 执行已配置的 restic 备份,可选先导出数据库 |
| issue_cert | 为某个域名签发 Let's Encrypt 证书,或续期所有到期的证书 |
| update_packages / deploy_app | 安装待更新的软件包,或重新部署一个 pm2 应用 —— 都是后台任务,用 list_jobs 跟进 |
开启之前有两件事值得知道:
- 日志内容属于不可信输入。 容器名、进程名和日志行都来自你无法掌控的软件,而它们会进入模型的上 下文 —— 旁边就摆着能重启和部署的工具。一行读起来像指令的日志并不是指令。真正限制损害的是动作清 单:里面没有任何工具会删数据或执行任意命令,且每一次调用都被审计。如果你更想要“注入了也无处下 手”的那种保证,就别开这个端点。
- token 是覆盖整个机群的操作凭据。 它能读出每台服务器的主机名、开放端口、已装软件包和日志内容, 也能在所有机器上重启和部署。请像对待主密码一样对待它,别在没有 HTTPS 的情况下把端点放到公网。
多语言
基于 next-intl,不使用 i18n 路由 —— 语言来自 myops_lang cookie 而不是
URL 前缀,因此所有路径保持不变。默认越南语,另带英语、中文、韩语和日语。
// Client component
const t = useTranslations("firewall");
t("ufwSummary", { fw: "UFW", status: "on", rules: 12, jails: 3 });
// Server component
const t = await getTranslations("meta");翻译文本放在 messages/<locale>.json —— 每种语言一个文件,键集完全一致,使用 ICU 语法(含英语复数)
。键在构建期由 src/global.d.ts 里的 AppConfig 声明做类型校验 —— 写错就是 TypeScript 错误。切换语
言用 useSetLocale(),它写入 cookie 后调用 router.refresh()(消息在服务端解析,必须走一次往返)。
新增语言:在 src/lib/lang.ts 的 LOCALES 里加上它,更新 parseLang,然后创建
messages/<locale>.json。
数据库
schema 以带版本的迁移随源码一起走,放在 prisma/migrations/。scripts/db-setup.ts 由 predev /
prestart 钩子触发,所以新克隆的仓库只要 yarn dev,已有安装则自动补上缺失的迁移。
| 情况 | 脚本会做什么 |
| ------------------------------- | ------------------------------------------------- |
| 还没有 dev.db | 创建文件,再 prisma migrate deploy 应用全部迁移 |
| 数据库是用 db push 建的(旧) | 把 0_init 标记为已应用(baseline),再补其余 |
| 已经在用迁移 | 只应用缺失的那些 |
改完 prisma/schema.prisma 后,用 yarn db:migrate --name <name> 生成迁移并提交产生的目录。不要
再用 prisma db push:它就地改数据库,不留下任何可供其他机器应用的东西。
脚本
| 命令 | 说明 |
| -------------------------------- | -------------------------------------- |
| yarn dev | 开发模式的自定义服务(tsx watch) |
| yarn build / yarn start | 生产构建与运行 |
| yarn format / format:check | Prettier 写入 / 检查 |
| yarn lint / yarn typecheck | ESLint 与 tsc --noEmit |
| yarn db:migrate --name <name> | 根据 schema 变更生成迁移 |
| yarn db:setup | 手动应用迁移(dev/start 也会做) |
| yarn db:studio / db:generate | Prisma Studio · 重新生成 Prisma Client |
任何改动收尾前都请跑一遍 yarn format && yarn lint && yarn typecheck。
环境变量
| 变量 | 必填 | 说明 |
| ----------------------- | ---- | ---------------------------------------------- |
| DATABASE_URL | 是 | file:./dev.db(相对 prisma/schema.prisma) |
| MYOPS_MASTER_KEY | 是 | 凭据加密密钥,至少 32 个字符 |
| MYOPS_HOME | 否 | .env 与 SQLite 文件的存放位置 —— 见下文 |
| PORT、HOSTNAME | 否 | 默认 3000 / localhost |
| MYOPS_INSECURE_COOKIE | 否 | 在局域网用纯 HTTP 跑生产环境时设为 1 |
| MYOPS_MCP_TOKEN | 否 | MCP 端点凭据;首次运行时自动生成 |
MYOPS_HOME 决定那两个无可替代的文件放在哪里。不设置时,若工作目录里能找到 .env 或
prisma/schema.prisma,myOps 就用工作目录 —— 源码检出和 Docker 镜像因此都维持原有位置。其他情况下
退回 ~/.myops,这样即使代码装在一个随时会被替换的目录里,密钥也能跨版本留存。
数据保留
原始指标保留 24 小时;超过之后每 5 分钟只留一个采样;超过 30 天则删除。清理任务每小时跑一次,同时 清掉过期会话。
安全须知
- 弄丢
MYOPS_MASTER_KEY就等于弄丢全部 SSH 凭据 —— 没有找回途径。请把密钥备份到prisma/dev.db之外的地方。 - API 永远不返回凭据本身,只返回一个
hasCredential标记。 - 主机密钥采用首次使用即信任:第一次连接会记下 SHA256 指纹,之后每次都必须一致,因此一台开始用不同 密钥应答的机器会被拒绝,而不是把已存凭据递过去。重装过的机器需要在该服务器的设置页里手动忘记一次 旧密钥。
- 把 myOps 暴露到局域网之外必须在前面加带 HTTPS 的反向代理:会话 cookie 以及全部文件与终端操作都走 这条连接。
- 文件操作与终端会话都会写入
AuditLog(终端按键内容不记录)。 MYOPS_MCP_TOKEN是覆盖整个机群的操作凭据 —— 见 MCP 服务。它在首次运行时生成;在.env里清空并重启后,/mcp就不复存在。
参与贡献
先看 CONTRIBUTING.md,再看 AGENTS.md 和
conventions.md —— 它们定义了本代码库遵循的分层、命名、i18n 与注释规则。目前还没有
测试框架,验证方式是 yarn format && yarn lint && yarn typecheck。
发现安全问题?请不要开公开 issue —— 见 SECURITY.md。
许可证
采用 Apache License 2.0。你可以使用、修改并自托管 myOps,包括商业用途,只要保留许可证与 版权声明,并注明你所做的修改。
Copyright © 2026 myOps. Licensed under the Apache License, Version 2.0.
