基于 Web 的服务器监控平台,支持实时 SSH 终端。
使用 Claude Code & DeepSeek-v4-pro 构建
公开探针每 15 秒刷新一次,只展示匿名节点编号、手动配置的公开位置、标签、可用性以及取整后的 CPU、内存和运行时间等健康指标。接口不会返回真实服务器名称、IP / 主机名、端口、SSH 用户、凭据、备注或数据库 ID。
安全提示: 管理功能涉及登录令牌和 SSH 凭据,请仅在域名已配置有效 HTTPS 证书并强制跳转 HTTPS 后使用。上面的链接仅指向匿名公开状态页。
| 层级 | 技术 |
|---|---|
| 后端 | Go + Gin + PostgreSQL |
| 前端 | React 19 + TypeScript + Vite + Ant Design |
| 实时通信 | WebSocket(SSH 终端) |
| 状态管理 | Zustand |
| 图表 | Recharts |
| 容器化 | Docker + Docker Compose |
| CI/CD | GitHub Actions → GitHub Container Registry |
| 模块 | 能力 |
|---|---|
| 服务器面板 | 卡片 / 列表双视图(记忆选择)、搜索、按标签与在线状态筛选、按 CPU / 内存 / 磁盘 / 运行时长 / 到期时间排序 |
| 概览指标 | 总数、在线 / 离线、平均 CPU 与内存、按月折算并换算币种的支出汇总 |
| 机器详情 | 资源指标磁贴、CPU / 内存 / 网络 / 磁盘 I/O / 负载 / 延迟六组图表(自适应单位、随明暗主题切换)、时间范围预设与自定义区间、历史数据导出 CSV |
| 告警中心 | 阈值规则 + 告警时间线,支持 Webhook 通知与连通性自测 |
| 批量操作 | 多选服务器后批量打/去标签、批量删除、导出资产清单 CSV、在最多 50 台上并发执行同一条命令并逐台查看结果 |
| 进程管理 | 详情页实时进程表,可按 PID / 用户 / CPU / 内存 / RSS / 运行时长排序,支持搜索、暂停自动刷新、结束进程(SIGTERM / SIGKILL) |
| 可用性统计 | 24 小时 / 7 天 / 30 天观测可用率,30 天每日条带与中断记录,概览页展示全站均值,公开状态页展示 30 天 SLA |
| 服务与端口 | 详情页 systemd 单元列表(失败优先)与启动/停止/重启/重载,以及监听端口表并按监听地址标注可达范围 |
| 运维操作 | SSH 网页终端、Docker 容器管理(启停 / 日志 / 交互终端、CPU / 内存 / 磁盘占用)、SSH 凭据集中管理、备注 |
| 账号安全 | 修改密码,并即时登出其他设备上的会话 |
| 公开状态页 | 匿名化探针页,接口层面即排除身份与连接信息 |
Web 新增主机/容器文件浏览、UTF-8 文本编辑及上传下载;Docker 页打开后自动分批加载容器。入口、支持范围、文件大小限制、外层代理配置见 文件管理说明。
告警规则在后端独立评估(默认每 30 秒一轮,ALERT_INTERVAL),只读取数据库中的最新采样,不会额外连接被监控主机。
- 指标:CPU、内存、磁盘使用率(%),1 分钟负载、网络延迟(ms),以及主机离线。
- 持续时长:阈值需连续满足设定时长才会开启告警,避免瞬时毛刺造成误报;离线规则最短 2 分钟,与面板的在线判定保持一致。
- 作用范围:可指定单台服务器,或留空以覆盖全部服务器(含之后新增的)。
- 通知:触发与恢复各向配置的 Webhook 地址 POST 一次 JSON(载荷格式见 docs/API.md),保存前可点「发送测试」验证链路。
- 状态持久化:进行中的告警以数据库记录表示,服务重启既不会重复通知,也不会漏掉恢复通知;主机长时间失联时阈值类告警自动收敛为已恢复,不会永久挂起。
可用率按观测口径计算:窗口内实际落库的指标样本数 ÷ 应落库的样本数。它衡量的是"我们是否看得到这台主机", 而不是主机自身的 uptime 计数器——面板或其数据库不可用的时段,会同时计入所有服务器的不可用时间。界面上固定标注了这一口径。
- 三个窗口:24 小时与 7 天读一分钟汇总层,30 天读 15 分钟层(一分钟层只保留 30 天,且逐台扫描它约是 20 倍的索引开销,而这点精度在一个月尺度上并不可见)。
- 不冤枉新机器:窗口起点会夹到服务器的创建时刻,刚加入的主机不会因为"加入之前没有数据"而被判为不可用;此时界面标注实际统计区间比标签更短。窗口尚未跨过一个完整的桶时显示「—」而不是 0%。
- 不永远差一个桶:窗口终点对齐到该汇总层的桶边界。正在填充中的桶还没有汇总落库,若把它算进应采集数,任何健康主机都永远到不了 100%。
- 每日条带:30 天逐日着色,与旁边的 30 天百分比同层统计,两者的数字因此一致。全天中断的那一天在查询结果里根本没有行,会被显式补齐,不会从图上消失;条带高度固定、只用颜色表达高低,否则 0% 的那天会是一根看不见的零高度条。服务器尚不存在的日子画成斜纹留白,与「整天 0%」区分开。
- 中断记录:由相邻汇总桶之间超过 2 分钟的间隔推导,最多列出最近 50 条,尚未恢复的一条会标为「进行中」。从未上报过任何样本的主机显示「暂无历史」,而不是「无中断」——没有样本可以作为中断的起点。
详情页新增「服务」与「端口」两个标签页,都走已有的 SSH 连接缓存,轮询只花一个 session。
服务
- 读取:优先
systemctl list-units,再补一次list-unit-files拿开机启动状态;没有 systemd 的主机(多数容器、老式 sysvinit)回退到service --status-all。 - 区分三种「问不到」:没装 systemd、装了但当前 SSH 用户问不到、以及主机根本没有任何服务管理器 —— 三者提示完全不同。特别地,在 systemd 主机上不会回退去读 init 脚本:无特权读取会把正在服务的 nginx 报成已停止,给出确定错误的数据比承认问不到更糟。
- 排序:失败 → 运行中 → 启动中 → 其余,各组内按名称排序。列表上限 500 条,因此被截断掉的一定是最不需要关注的那些。
- 状态显示:
active旁边带上sub状态(running / exited / dead)—— 它才是区分「一次性任务已完成」和「守护进程已死」的字段。开机启动状态为空显示为—,不会当作「已禁用」。 - 控制:启动 / 停止 / 重启 / 重载。四个动词用文字而非图标 —— 重启和重载在小尺寸下都是「一圈箭头」,而选错不是无伤大雅的失误:重启会断开该服务上的所有连接。
reload单列一个动词正是因为它不断连接;Windows 没有对应语义,会直接拒绝而不是悄悄降级为重启。 - 不提权:以服务器配置的 SSH 用户执行,不尝试 sudo。无权时把主机自身的拒绝信息原样展示。单元名经严格白名单校验(且在建立连接之前),shell 元字符一律拒绝。
端口
- 读取:
ss -tulnp,失败回退netstat -tulnp。两者格式差别不小,各有独立解析:UDP 在 ss 里的状态是UNCONN而非LISTEN,按字面过滤会丢掉全部 UDP 监听;netstat 的进程列装的是被列宽截断的进程标题(sshd 显示为sshd: /usr/sbin)。 - 可达范围:由监听地址推导并着色 —— 通配监听(
0.0.0.0/::)标为公网可达并单独提示,RFC1918 与 link-local 标为内网,127.0.0.0/8与::1标为仅本机。这是这个页面的主要价值:它直接回答「谁能连上这个端口」。 - 常见端口会显示服务名(22 → ssh,5432 → postgres)。进程归属为空表示当前 SSH 用户无权查看,不代表没有归属进程。
在服务器面板点击「批量选择」进入多选,卡片与列表视图均可勾选,底部浮出操作栏。
- 批量标签 / 批量删除 / 导出清单:标签添加是幂等的;删除会级联清理历史指标、告警记录与标签关联;导出的清单不含任何密钥(接口本身就不返回)。
- 批量执行命令:最多 50 台,8 台并发,单台限时 60 秒、输出上限 64 KB。执行前的确认弹窗会完整列出命令和全部目标主机;命令必须为单行,含
rm -rf、reboot、写块设备等模式时会额外提示。 - 逐台返回退出状态与合并输出(stdout + stderr),单台失败不影响其余主机。以服务器配置的 SSH 用户执行,不会尝试 sudo 提权。
- 用户密码使用 bcrypt(cost factor 12)哈希存储,即使数据库泄露也无法还原明文密码
- 密码要求最少 6 位,用户名 3-64 位,防止弱口令
- 所有服务器的 SSH 密码和密钥在写入数据库前使用 AES-256-GCM 加密
- 加密密钥独立于数据库存储(通过环境变量
ENCRYPTION_KEY注入),数据库泄露也无法解密凭据 - AES-256-GCM 提供认证加密(Authenticated Encryption),同时保证机密性和完整性
- 基于 JWT(HS256) 的无状态认证,Token 有效期 72 小时
- 修改密码会立即吊销该账号此前签发的全部 Token:用户表记录一个失效时间点,鉴权时拒绝
iat更早的 Token。发起修改的那个会话会收到新签发的 Token,不会被自己的操作切断 - 所有 API 请求通过 Bearer Token 认证,WebSocket 通过 Query Token 认证
- 所有受保护的管理 API 查询强制按
user_id过滤,用户之间数据完全隔离;公开探针使用独立的最小化数据模型,只返回匿名健康指标
- 登录和注册接口启用 令牌桶限流(5 次/分钟/IP),防止暴力破解和恶意注册
- 注册接口默认开放;账号创建完毕后可用
ALLOW_REGISTRATION=false关闭,此后POST /api/auth/register一律返回 403 - 请求参数通过结构体绑定自动校验,防止非法输入
- 支持配置 CORS 白名单,限制跨域请求来源
- 告警 Webhook 默认拒绝内网目标:解析到 loopback / RFC1918 / link-local / CGNAT 地址的地址会在保存时被拒绝,且请求不跟随重定向,避免被当作 SSRF 跳板探测服务端内网(可用
ALLOW_PRIVATE_WEBHOOKS=true显式放开)。Webhook 自测接口另有 6 次/分钟/IP 限流
- 支持 TLS/HTTPS(可配置证书和私钥文件)
- 生产环境建议通过反向代理(Nginx)启用 HTTPS
- Docker 镜像基于 Alpine Linux 最小化构建,减少攻击面
- 后端容器内进程以 非 root 用户 运行,仅
ping二进制携带CAP_NET_RAW能力用于延迟探测 - 敏感配置(数据库密码、JWT 密钥、加密密钥)通过 GitHub Secrets 管理,不写入代码
- 数据库使用
ON DELETE CASCADE外键约束,确保数据一致性
| 目录 | 内容 |
|---|---|
web/ |
网页版:backend/(Go + Gin)、frontend/(React)与 docker-compose.yml,由 GitHub Actions 构建镜像并部署 |
macos/ |
macOS 原生客户端(SwiftUI,纯本地,不依赖服务端) |
windows/ |
Windows 原生客户端(.NET 10 + WPF,纯本地,不依赖服务端) |
docs/ |
接口文档 API.md 与截图 |
三个客户端各有自己的工作流:改 web/ 触发网页版部署,改 macos/、windows/ 只触发各自的构建,互不影响。
macos/ 下是一个纯本地的 SwiftUI 菜单栏应用,不依赖本项目的服务端:它直接用系统 ssh 连接各台主机采集指标(Linux 与 Windows),历史存在本机 SQLite,界面对标 SwiftServer——仪表板、机器详情卡片、Docker、SFTP、终端、代码片段、vnStat 流量统计,并常驻菜单栏在后台持续轮询与告警。构建、测试与打包见 macos/README.md。
windows/ 是功能对等的 Windows 版(.NET 10 + WPF),同样纯本地、同样直连主机,托盘常驻:仪表板、机器详情、Docker 五表、SFTP、终端、代码片段、SSH 密钥、会话历史、Toast 告警与开机自启,界面文案与 macOS 端同源。默认走进程内的 SSH 长连接(相当于 macOS 端的 ControlMaster;Windows 自带的 ssh.exe 不支持连接复用),需要 Match 块、证书或真正的 ssh-agent 的主机可以逐台改用系统 ssh.exe。构建、测试、打包与已知缺口见 windows/README.md,技术决策与分阶段计划见 windows/PLAN.md。
发布包是自包含单文件,目标机器不需要装 .NET;但没有代码签名,首次运行 SmartScreen 会拦一次。
# 后端
cd web/backend
cp .env.example .env # 编辑配置文件
go run ./cmd/server
# 前端
cd web/frontend
npm install && npm run dev项目通过 GitHub Actions 自动构建 Docker 镜像并部署到服务器。Push 到 main 分支或手动触发 workflow 即可。
发布前执行后端测试与前端浏览器回归,按本次 SHA 发布;部署后校验数据库就绪与生产页面,失败自动回滚。生产配置持久保存在 /opt/server-monitor/shared/.env,首次升级自动保留旧 web/.env,不再从 GitHub Secrets 重写应用配置。新部署须先配置 shared/.env;迁移、必要配置、手动回滚与保留策略见 Web 发布说明。
- 服务器已安装 Docker 和 Docker Compose
- 服务器已配置 PostgreSQL 数据库
- 域名已解析到服务器 IP
在仓库的 Settings → Secrets and variables → actions 中添加以下 Secrets:
| Secret | 说明 | 示例 |
|---|---|---|
DEPLOY_HOST |
服务器 IP 或域名 | 1.2.3.4 |
DEPLOY_USER |
SSH 登录用户名 | root |
DEPLOY_PASSWORD |
SSH 登录密码 | - |
DOMAIN |
网站域名 | svr.hmchxd.com |
GHCR_PAT |
GitHub 个人访问令牌(read:packages 权限) | 见下方说明 |
GITHUB_TOKEN由 GitHub 自动提供,无需手动配置。GHCR_PAT 说明:部署服务器需要从 GitHub Container Registry 拉取私有镜像,请到 GitHub Settings → Tokens 创建一个 Personal Access Token (classic),勾选
read:packages权限,将生成的 token 填入此 Secret。
| 主页 / 仪表盘 |
|---|
![]() |
| 机器详情 | SSH 终端 |
|---|---|
![]() |
![]() |
- CI/CD 集成 — GitHub Actions 自动 lint / build / test / deploy
- 修改机器信息 — 已添加的服务器支持修改 host / port / SSH 凭据等配置
- 登录历史 — 登录成功后右下角弹窗显示上次登录的 IP、时间和地理位置
- Docker 管理 — 机器详情页可查看 Docker 容器列表、状态及 CPU / 内存 / 磁盘占用
- SSH 密钥管理 — 独立管理 SSH 密钥(创建、命名、关联服务器),避免重复粘贴
- SSH 账号密码管理 — 像管理 SSH 密钥一样管理通用的账号密码
- 账号密码管理 — 设置页可修改密码,并即时吊销其他设备上的会话
- 机器组 / 批量操作 — 标签已承担分组职责,本项落地为批量操作:批量标签、批量删除、批量执行命令、导出清单
- 可用性统计 — 观测口径的 24h / 7d / 30d 可用率、每日条带与中断记录,详见下文
- 服务管理 / 端口检查 — systemd 单元列表与控制、监听端口及其可达范围,详见下文
- 进程列表 — 详情页实时进程表,支持排序、搜索与结束进程
- 磁盘占用 — 详情页展示当前磁盘使用占比
- 告警通知 — 阈值规则(CPU / 内存 / 磁盘 / 负载 / 延迟 / 离线)+ Webhook 推送,详见下文
- 公开探针 — 提供匿名化公开状态页和最小化状态 API,隐藏服务器身份与连接信息


