Zum Inhalt springen

HTTP API

Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.

Web UI 所做的一切都经过 /api/*,同一套 API 也向你自己的脚本、仪表板和助手开放:不存在私有的另一半。它是基于 HTTP 的纯 JSON,通过会话 cookie(Web UI)或 API 令牌(其他一切)认证。

每个实例都以 OpenAPI 3.1 文档描述自己的 API:

GET /api/openapi.json

它是公开的——不含机密、地址,也不含任何关于你监控项的信息——并且是详尽的参考:客户端可调用的每个路由、其参数、请求和响应格式、错误响应,以及所需的范围(每个操作上的 x-token-scope 扩展:public、read、write,或对令牌永远无法调用的路由为 none)。本页下文的表格是同一内容的易读摘要。

有意省略的内容:代理协议(/api/ingest、/api/agent/commands*、/api/agent/relay*),只有代理使用;SSO 登录的浏览器重定向(/api/auth/oidc/start、/api/auth/oidc/callback)和 Spotify 的重定向(/api/music/spotify/callback);以及代理下载(/install.sh、/install.ps1、/download/*)。

可在任何 OpenAPI 工具中加载:

Terminal window
# Browse it, and try calls with your token, in Swagger UI
docker run --rm -p 8081:8080 \
-e SWAGGER_JSON_URL=http://monit.lan:8080/api/openapi.json swaggerapi/swagger-ui
# then open https://localhost:8081 and paste "dmt_…" under Authorize → bearerAuth
# Generate a client library (here Python)
docker run --rm -v "$PWD:/local" openapitools/openapi-generator-cli generate \
-i http://monit.lan:8080/api/openapi.json -g python -o /local/dumbmonit-client
# Or just list what is there
curl -s http://monit.lan:8080/api/openapi.json | jq -r '.paths | keys[]'

Postman 和 Insomnia 可从同一 URL 导入。

有两种方式,在每个受保护的路由上都被接受:

  • 会话 cookie——Web UI 使用的方式。使用密码(或 SSO)登录,并发送 HttpOnly 的 dumbmonit_session cookie(SameSite Lax;当 DUMBMONIT_COOKIE_SECURE=1 时为 Secure;30 天)。每个改变状态的请求(POST、PUT、DELETE)还必须携带 X-Requested-With: DumbMonit——这是 UI 自动添加的防 CSRF 证明;没有它,请求会以 403 被拒绝。
  • API 令牌——Authorization: Bearer dmt_…,供脚本、仪表板和助手使用。在设置 → API 与助手中创建(与 MCP 服务器使用的是同一种令牌),只显示一次。不涉及 cookie,因此永远不需要 X-Requested-With 头。
Terminal window
# API token: one header, nothing else
curl -H 'Authorization: Bearer dmt_…' http://monit.lan:8080/api/targets
curl -H 'Authorization: Bearer dmt_…' -X POST http://monit.lan:8080/api/targets/4/probe
# Session: sign in (204 and a Set-Cookie header), then send the cookie
curl -c cookies.txt -X POST http://monit.lan:8080/api/auth/login \
-H 'content-type: application/json' \
-d '{"username":"admin","password":"…"}'
curl -b cookies.txt http://monit.lan:8080/api/targets
curl -b cookies.txt -X POST http://monit.lan:8080/api/targets \
-H 'X-Requested-With: DumbMonit' -H 'content-type: application/json' \
-d '{"name":"NAS","address":"nas.lan","kind":"snmp","credential":{"type":"snmp_community","community":"public"}}'

当请求携带 bearer 令牌时,cookie 会被忽略:已吊销的令牌即使来自已登录的浏览器也会被拒绝,而不是悄悄回退到会话。

代理注册令牌(dmon_…)是另一回事:它们只在代理路由(/api/ingest、/api/agent/commands/*、/api/agent/relay*)上有效。它们表明某台机器可以通信,而不是哪一台机器:在这些路由上,已绑定的机器还必须在 X-DumbMonit-Agent-Secret(dmab_…)中出示自己的绑定密钥,该密钥由服务器在注册时一次性下发。参见绑定。

登录受到速率限制:失败五次后,每次后续尝试都会被以 429 拒绝,并带有 Retry-After 延迟,该延迟从 30 秒起翻倍,最长 5 分钟。切勿在循环中猜测密码。

令牌有两种范围之一。没有第三种更强大的范围:管理员在自己账户上所做的事情,任何令牌都无法触及。

read 令牌write 令牌
查看者账户可以发起的每个 GET(监控项、告警、指标、规则、不含机密的渠道、状态页面……)是是
管理员可以发起的 POST、PUT、DELETE(监控项、规则、静默、渠道、状态页面、包、探测、发现……)403是
/metrics、/federate、/prometheus/*(抓取)是是
MCP 读取工具 / 写入工具(助手)仅读取两者
账户、会话、双因素、SSO、审计日志(/api/auth/*、/api/users/*)403403
API 令牌和代理注册令牌(/api/tokens/*、/api/agent/tokens/*)403403
备份与恢复(/api/backup/*)403403

read 令牌访问写入路由时会得到 403,消息中指明该令牌和缺少的范围。由于没有任何令牌可以列出、创建或吊销令牌,令牌永远无法铸造另一个令牌——更不用说更强大的令牌了。

  • 只显示一次,哈希存储。 令牌是 dmt_ 后跟 128 位随机数。服务器只保留其 SHA-256 摘要(以及开头的字符,dmt_1a2b3c4d,用于在列表中识别它);明文令牌只存在于创建它的响应中。出示的令牌以恒定时间比较。
  • 有效期。 创建时可选择 30 天、90 天、1 年或永不过期。过期的令牌会得到 401,消息为 The API token "<name>" expired on …,并带有 WWW-Authenticate: Bearer error="invalid_token";它会留在列表中并标记为已过期,直到你吊销它。
  • 允许的网络。 可选择将令牌限制在一组地址或 CIDR 范围内(192.168.1.0/24, 10.8.0.5,最多 32 项)。从其他任何地方使用都会得到 403,消息为 The API token "<name>" cannot be used from <address>. 所检查的地址是 TCP 客户端的地址,或者——仅当连接来自列于 DUMBMONIT_TRUSTED_PROXIES 的代理时——该代理在 X-Forwarded-For 中报告的地址。在你未声明的反向代理之后,每个请求看起来都来自代理:请声明它,否则该限制会拒绝所有人。
  • 最近使用。 令牌列表显示每个令牌最近一次使用的时间和来源地址(最多每分钟更新一次,地址变化时立即更新):没人再使用的令牌就该吊销。
  • 绑定到其创建者。 令牌会记住创建它的账户。如果该账户被停用,其令牌会被拒绝(401);如果它被降级为操作员或查看者,其 write 令牌会按 read 令牌处理;如果它被删除,其令牌会被吊销。
  • 吊销立即生效:下一次调用得到 401。
  • 有日志。 用令牌发起的每次写入都会记录到服务器日志,包含令牌的名称和 id、方法、路径(不含查询字符串)和状态——绝不记录令牌,绝不记录正文。创建和吊销令牌记录在审计日志中(设置 → 安全)。

每个令牌每分钟可发起 120 次调用,REST 和 MCP 合计。超过之后,调用会被以 429 和 Retry-After 头(秒)拒绝,直到这一分钟结束。对使用令牌认证的请求的每个响应都会告诉你当前状况:

头含义
RateLimit-Limit每个窗口允许的调用数(120)。
RateLimit-Remaining当前窗口中剩余的调用数。
RateLimit-Reset窗口重新开始前的秒数。

面板很多且刷新很快的 Grafana 仪表板可能会达到限制:请给它单独的令牌,或延长刷新间隔。

来自其他源的页面——你自己的仪表板、Swagger UI、基于浏览器的 MCP 客户端——可以**使用 bearer 令牌(绝不使用会话)**调用 API:

  • 仅当请求携带 Authorization: Bearer dmt_… 时(或针对公开的 GET /api/openapi.json),响应才带有 Access-Control-Allow-Origin。绝不发送 Access-Control-Allow-Credentials,因此浏览器永远不会在跨源调用中附带会话 cookie;
  • 对 /api/* 的预检(OPTIONS)仅当所声明的头包含 authorization 时才成功:204,方法 GET, POST, PUT, DELETE,头 authorization, content-type, mcp-protocol-version, mcp-method, mcp-name,缓存 10 分钟。其中不含 X-Requested-With,因此基于 cookie 的会话永远无法从另一个源发起写入;
  • Retry-After、WWW-Authenticate、RateLimit-* 头以及 X-DumbMonit-Api-Version 可被调用方脚本读取。

DUMBMONIT_API_CORS_ORIGINS 设置允许哪些源:

值效果
未设置(默认)任意源(Access-Control-Allow-Origin: *)。是安全的,因为只有 bearer 令牌才能打开任何东西。
https://grafana.example.com,https://dash.lan仅这些源,原样回显。
off完全没有 CORS 头:仅同源页面和非浏览器客户端。

同一份列表还决定 MCP 端点接受哪些 Origin。

// From a page on another origin. Never ship a write token in a public page.
const response = await fetch('https://monit.example.com/api/alerts', {
headers: { Authorization: 'Bearer dmt_…' }
});
if (!response.ok) throw new Error((await response.json()).error);
const alerts = await response.json();
console.log(response.headers.get('RateLimit-Remaining'), 'calls left this minute');

/api 下的每个响应都带有 API 版本:

X-DumbMonit-Api-Version: 0.1

同一个值是 OpenAPI 文档中的 info.version,旁边是 x-server-version,即响应请求的服务器版本。当 API 处于 0.x 时,它并未冻结;每当删除或重命名某个路由或字段时版本就会变化。添加路由或字段不会改变它:请忽略你不认识的字段。

每个错误都是 JSON:{"error": "message"},用人能读懂的语言写成。

状态何时出现
400请求格式错误或某个值无效;消息会指明。
401没有有效的会话或令牌:令牌缺失、未知、已吊销或已过期(带 WWW-Authenticate: Bearer),或令牌的创建者已被停用。
403已认证但不被允许:查看者、告警处理之外的操作员、在写入路由上的 read 令牌、访问账户/令牌/备份路由的令牌、从不被允许的网络使用的令牌、没有 X-Requested-With 的 cookie 写入,或在公开演示上的任何写入(带 "demo": true)。
404id 不存在。/api 下不匹配任何路由的路径返回 404 {"error": "Unknown API route: …"},而不是 Web UI 的 HTML。
405该路径上不存在此方法(例如 GET /api/mcp)。
409与当前状态冲突(重复、命令已在运行……)。
429被限速,带 Retry-After。
500服务器故障;详情在服务器日志中,绝不在响应里。
Terminal window
$ curl -i -H 'Authorization: Bearer dmt_revoked…' http://monit.lan:8080/api/targets
HTTP/1.1 401 Unauthorized
www-authenticate: Bearer
{"error":"A valid API token is required."}
$ curl -i -X DELETE -H 'Authorization: Bearer dmt_…read…' http://monit.lan:8080/api/targets/4
HTTP/1.1 403 Forbidden
{"error":"This action needs a token with the \"write\" scope; the token \"Grafana\" is \"read\" only. Create a write token in Settings → API & assistants."}
$ curl -i -H 'Authorization: Bearer dmt_…' http://monit.lan:8080/api/alerts # the 121st call this minute
HTTP/1.1 429 Too Many Requests
retry-after: 17
ratelimit-limit: 120
ratelimit-remaining: 0
{"error":"Rate limit reached (120 calls per minute per token). Retry in 17 s."}

MCP 端点则改用 JSON-RPC 响应,并使用自己的错误代码。

在下面的表格中,会话指会话 cookie 或 API 令牌;管理员指管理员会话或 write 令牌;操作员指操作员或管理员会话,或 write 令牌;仅会话指会话 cookie,绝不是令牌。

角色。 viewer 账户可发起所有 GET。operator 可进行同样的读取,外加本页中标为操作员的告警处理写入(OpenAPI 文档中为 x-roles: [admin, operator]):确认、暂缓(维护窗口)、对某监控项忽略某条规则、清除已解决的历史。其他所有写入仅限管理员,对操作员返回 403。

方法路由认证用途
GET/api/auth/status公开{"configured": bool, "authenticated": bool, "user": …, "oidc": {"enabled", "provider_name", "login_url"}}。configured: false 表示全新实例:在第一个管理员存在之前,每个标为会话的路由都返回 401——只有 status、setup、login 和 health 可访问。
POST/api/auth/setup公开{"setup_code": "…", "username": "admin", "password": "…"}。在全新实例上创建第一个管理员(至少 12 个字符);username 可省略,此时为 admin。setup_code 是启动时打印在服务器日志中的一次性代码(或 DUMBMONIT_SETUP_CODE);大小写、连字符和空格会被忽略。204;不会开启会话。代码错误返回 401,过多次数后返回 429,账户已存在时返回 409。
POST/api/auth/login公开{"username": "…", "password": "…"}。204 并带 Set-Cookie。密码错误返回 401,被限速时返回 429。当账户启用了双因素时,改为返回 200 及 {"totp_required": true, "pending": "…"}——一张有效期五分钟、输错五次验证码后失效的凭证:用 /api/auth/login/totp 完成登录。
POST/api/auth/login/totp公开{"pending": "…", "code": "123456"}——第一步得到的凭证和一个验证码(或恢复码)。204 并带会话 cookie。
GET/api/auth/oidc/start公开将浏览器重定向到身份提供方。
GET/api/auth/oidc/callback公开从提供方返回(code、state):开启会话并重定向到 UI。
GET/api/auth/me仅会话当前账户:id、username、display_name、role(admin、operator、viewer)、auth(password、oidc)、disabled、totp_enabled、created_at、last_login_at。
POST/api/auth/logout仅会话结束会话并清除 cookie。
POST/api/auth/password仅会话{"current_password": "…", "new_password": "…"}。使所有其他会话登出。
GET/api/auth/totp仅会话当前账户的双因素状态:enabled、pending、recovery_codes_left。
POST/api/auth/totp/enroll仅会话{"password": "…"}。提出一个密钥:secret(base32)、otpauth_uri、issuer、account。在验证之前不会强制执行任何内容。
POST/api/auth/totp/verify仅会话{"code": "123456"}。确认注册并返回 {"recovery_codes": […]}——只显示一次。
DELETE/api/auth/totp仅会话{"password": "…"}。移除第二因素。204。
GET/api/auth/audit?limit=200管理员,仅会话最近的安全事件:id、at、actor、action(login、login.failed、password.changed、token.created、user.updated、……)、subject、ip。
GET/api/auth/oidc/config管理员,仅会话SSO 设置及其来源(环境变量或数据库);绝不返回 client secret。
PUT/api/auth/oidc/config管理员,仅会话{"issuer", "client_id", "client_secret", "provider_name", "scopes", "auto_create", "admin_groups", "groups_claim", "public_url"}。缺失或为空的 client_secret 保留已存储的值;缺失的 auto_create 表示关闭。
DELETE/api/auth/oidc/config管理员,仅会话忽略已存储的 SSO 设置(如有环境变量,则重新生效)。204。
POST/api/auth/oidc/test管理员,仅会话获取提供方的发现文档并报告所发现的内容。
GET/api/users管理员,仅会话每个账户,格式同 /api/auth/me。
POST/api/users管理员,仅会话{"username", "display_name", "role", "password"}。仅当启用了 SSO 时 password 才可省略。201。
PUT/api/users/{id}管理员,仅会话display_name、role、disabled、password 中的任意项;省略的字段保持原值。不能降级或停用最后一个管理员。
DELETE/api/users/{id}管理员,仅会话204。不能是你自己,也不能是最后一个管理员。
DELETE/api/users/{id}/totp管理员,仅会话重置另一个账户的第二因素(被锁定的同事)。204。
GET/api/tokens仅会话每个 API 令牌:id、name、prefix、scope、created_at、created_by(创建它的账户)、expires_at(null:永不过期)、expired、allowed_networks(空:任何地方)、last_used_at、last_used_ip、revoked_at。绝不返回密钥。
POST/api/tokens管理员,仅会话{"name": "Grafana", "scope": "read", "expires_in_days": 90, "allowed_networks": ["192.168.1.0/24"]}。name 必填(最多 80 个字符);scope 为 read(默认)或 write;expires_in_days 范围 1 到 3650,null 或缺失表示永不过期的令牌;allowed_networks 最多接受 32 个地址或 CIDR 范围,以网络形式存储(192.168.1.7/24 变为 192.168.1.0/24),为空或缺失表示任何地方。201,返回令牌字段外加 secret(只显示一次)。400 会指出无效的网络。
DELETE/api/tokens/{id}管理员,仅会话吊销。204;未知或已吊销时返回 404。

列表中的令牌:

{
"id": 3, "name": "Grafana", "prefix": "dmt_1a2b3c4d", "scope": "read",
"created_at": "2026-10-01T09:12:00Z", "created_by": "admin",
"expires_at": "2026-12-30T09:12:00Z", "expired": false,
"allowed_networks": ["192.168.1.0/24"],
"last_used_at": "2026-10-01T09:30:00Z", "last_used_ip": "192.168.1.20",
"revoked_at": null
}

除了 X-DumbMonit-Api-Version(版本控制)、RateLimit-* 头(速率限制)和 CORS 头(跨源请求)之外,每个响应还带有 X-Content-Type-Options: nosniff、Referrer-Policy: same-origin 和 Content-Security-Policy。该策略从 default-src 'none' 开始,只开放界面真正用到的内容——全部由 DumbMonit 自己提供:

default-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;
font-src 'self'; connect-src 'self'; base-uri 'none'; form-action 'self';
script-src 'self' 'nonce-<per response>'; frame-ancestors 'none'

其中没有第三方源,也永远不应该有:字体、图表库和所有资源都打包在二进制文件中。页面的内联脚本(首次绘制前应用的主题、SvelteKit 的引导程序)由为每个响应重新生成的 nonce 允许,因此 'unsafe-inline' 绝不适用于脚本。它确实适用于样式,并且无法移除:Svelte 会在元素上设置 style= 属性,而 nonce 和哈希都无法覆盖它们。

公开状态页面是为嵌入而设计的:/s/<slug> 及其紧凑视图 /s/<slug>/embed——仅这两个——获得相同的策略,但不含 frame-ancestors。其他所有内容,包括 /s/ 下的订阅确认和退订页面,也都带有 X-Frame-Options: DENY。

如果你把 DumbMonit 放在反向代理之后,不要让它再添加第二个 Content-Security-Policy 头:浏览器会强制执行所有策略的交集,而没有 nonce 的代理默认策略会导致空白页面。

方法路由认证用途
GET/api/health公开服务器版本及其依赖项的状态。始终为 200:失败的组件在响应正文中。
GET/api/update会话或令牌运行中的版本、最新发布版本、update_available;服务器每天最多询问 GitHub 一次。POST /api/update/check 立即检查,PUT /api/update/settings 开启或关闭检查。参见更新。
{"status":"ok","version":"0.1.0","database":{"ok":true},"victoria":{"ok":true,"embedded":true}}

组件失败时 status 为 degraded;该组件随后会带有一个 error 字符串。当服务器运行自己的 VictoriaMetrics 时 victoria.embedded 为 true,DUMBMONIT_VM_URL 指向外部实例时为 false。

方法路由认证用途
GET/api/backup管理员,仅会话备份包将包含的内容(contents,每个分区一行及其数量)、备份包格式版本、实例密钥的位置(secret_source:file 或 environment)以及定时本地备份的状态(schedule)。
POST/api/backup管理员,仅会话{"passphrase": "…", "include_account_secrets": false}。将备份包本身作为 JSON 文件返回:明文头部(format、version、created_at、summary、kdf)和 payload,后者使用 AES-256-GCM 加密,密钥由口令通过 Argon2id 派生。至少 16 个字符,否则返回 400。
POST/api/backup/restore管理员,仅会话{"bundle": {…}, "passphrase": "…", "apply": false}。除非 apply 为 true,否则为试运行;二者运行相同的代码,试运行在被回滚的事务内进行。返回报告:每个分区的 created、updated、skipped 和 notes,外加 warnings。口令错误、文件被修改或备份包以更新的格式版本写成时返回 400。
POST/api/backup/local管理员,仅会话立即写入一份定时风格的本地备份,并返回新的 schedule。

备份包包含实例的所有凭据,并用口令重新加密,因此这些路由会拒绝 API 令牌并给出说明:只有登录 Web 界面的管理员才能使用。参见备份与恢复。

方法路由用途
GET/api/collectors此服务器可监控的每种监控项类型:kind、label、summary、examples、credential_types、address_hint、default_port、setup(title、steps、warning、doc_url)和 options(key、label、help、placeholder、default、required、input、choices)。由集成包带来的类型以同样方式列出,形式为 pack.<id>。

管理员会话或 API 令牌(更改需要 write 范围)。参见集成包。

方法路由用途
GET/api/packs已安装的包:id、version、label、summary、kind(仅含 SNMP 配置文件的包为 null)、enabled、installed_at、sha256、metrics、rules(uid)、snmp_profiles、targets(使用它的监控项)、warnings,以及已存储的包不再通过验证时的 error。
GET/api/packs/{id}一个包。
POST/api/packs安装或更新。正文:YAML(application/yaml、text/plain……)或 JSON 中的 {"yaml": "…"}。创建时返回 201,更新或未变化时返回 200,附带 outcome(created、updated、unchanged)、pack、rules_added 和 restart_required(SNMP 配置文件)。400 会列出每个验证错误。
PUT/api/packs/{id}/enable、/api/packs/{id}/disable注册或撤销该包的监控项类型;监控项、历史和规则保留。
DELETE/api/packs/{id}卸载,连同其规则。有监控项使用时返回 409。
方法路由用途
GET/api/targets列出每个监控项。
POST/api/targets创建一个。201 并返回该监控项。对 SNMP 会在后台开始配置文件检测。
GET/api/targets/{id}一个监控项。
PUT/api/targets/{id}替换它。省略 credential 会保留已存储的凭据;省略 profile_id 会保留检测到的配置文件("" 清除它)。设置 enabled: false 会清除该监控项的告警且不发送通知。
DELETE/api/targets/{id}204。清除该监控项的告警且不发送通知,并从 VictoriaMetrics 中删除其时间序列(尽力而为)。
POST/api/targets/{id}/probe立即探测:{"sample_count": 42, "series": ["if_octets_in{host=\"Core switch\",ifname=\"eth0\"}", …]}——序列键与采集器生成的一致,不含写入器在发往 VictoriaMetrics 途中添加的 dumbmonit_ 前缀。
POST/api/targets/{id}/discover重新运行配置文件检测:{"profile_id": "host-resources"} 或 null。

返回的监控项:

{
"id": 4,
"name": "Core switch",
"address": "192.168.1.2",
"kind": "snmp",
"profile_id": "host-resources",
"parent_id": null,
"via_agent": null,
"interval_secs": 60,
"enabled": true,
"tags": {"role": "network"},
"credential_kind": "SNMP community",
"last_probe_at": "2026-09-15 13:20:05",
"last_error": null,
"error_kind": null
}

机密本身绝不返回:credential_kind 只是一个标签。服务器时间戳为不带后缀的 UTC。error_kind 对 last_error 分类:down(监控项没有应答)或 config(我们这边的问题——凭据、地址、选项),UI 将其显示为不可达或配置错误;上一次探测成功时为 null。

创建一个:

{
"name": "Core switch",
"address": "192.168.1.10",
"kind": "snmp",
"interval_secs": 60,
"parent_id": null,
"tags": {},
"credential": {"type": "snmp_community", "community": "public"}
}

凭据格式(type):none;snmp_community(community);snmp_v3(username,可选的 auth: {protocol, passphrase},协议为 md5、sha1、sha224、sha256、sha384 或 sha512,可选的 privacy: {protocol, passphrase},协议为 des、aes128、aes192 或 aes256,可选的 context);api_token(token,或两部分 token_id 和 secret,服务器会为 Proxmox VE 和 PBS 将它们拼接成 user@realm!name=secret);username_password(username、password)。interval_secs 默认为 60,不能低于 10。name 最多 200 个字符,address 最多 253 个(超出则返回 400)。parent_id 必须指向一个已存在的监控项(400 Parent device N not found.)。类型选项以其键放在 tags 中。

via_agent 指明从自己网络探测监控项(而不是由服务器探测)的中继代理;null(默认)表示由服务器探测。它必须是一个 agent 监控项(否则 400),监控项不能中继自己,agent 监控项不能被中继。在 PUT 中,省略的 via_agent 会保留已存储的值,与 profile_id 和 credential 相同;发送 null 则恢复直接探测。对被中继监控项的 POST /api/targets/{id}/probe 和 /discover 会经由中继并等待其应答(探测已在进行中时返回 409,中继没有应答时返回 400 Timed out: relay agent …)。

方法路由认证用途
POST/api/discovery管理员{"cidr": "192.168.1.0/24", "community": "public", "port": 161, "timeout_ms": 1000}。扫描网络中的 SNMP 设备。cidr 必填;community 默认为 public;timeout_ms 被限制在 100–10,000 之间。超过 4096 个地址的网络会被拒绝。扫描是带 JSON 正文的 POST,因此 community 绝不会出现在 URL 或日志行中。
{
"scanned": 254,
"devices": [
{"address": "192.168.1.10", "sysname": "sw-core", "sysdescr": "…", "sysobjectid": "1.3.6.1.4.1.8072.3.2.10", "suggested_profile": "host-resources"}
]
}

概览在新实例上显示的三个步骤。状态保存在实例上而不是浏览器中,因此跳过某一步就是在所有地方跳过。

方法路由认证用途
GET/api/onboarding会话实例当前所处的状态。
PUT/api/onboarding管理员{"skipped": true} 将整个向导收起;{"dismissed": ["test"]} 将单个步骤收起。省略的字段保留其存储值;device、channel、test 之外的步骤 id 会返回 400。返回与 GET 相同的文档。
{
"skipped": false,
"complete": false,
"completed_at": null,
"dismissed": [],
"has_target": true,
"has_channel": true,
"notification_confirmed": false
}

has_target、has_channel 和 notification_confirmed 在每次读取时重新计算:它们是关于实例的事实,而不是界面设置的标志。notification_confirmed 在确实有消息从某个渠道发出之后为真——测试消息算数,仅仅创建了渠道则不算。

complete 是锁存的,永远不会变回 false。服务器在三个步骤都已解决(完成或已收起)时设置它,并且在首次读取一个已经有监控项和渠道的实例时也会设置——因此升级一个已有的实例永远不会向它显示首次运行向导。

两个路由都代理 VictoriaMetrics,并以 Prometheus 的格式返回序列:[{"metric": {labels…}, "values": [[timestamp_seconds, "value"], …]}]。

方法路由用途
GET/api/metrics/query?query=…即时 MetricsQL 查询。
GET/api/metrics/query_range?query=…&start=…&end=…&step=…范围查询。start 和 end 是自纪元起的毫秒;step 以秒为单位,并会被放宽,使一条序列绝不超过 2,000 个点。
Terminal window
curl -b cookies.txt -G https://localhost:8080/api/metrics/query \
--data-urlencode 'query=avg by (target, host) (dumbmonit_cpu_usage_percent)'
[{"metric":{"host":"ThinkpadE14","target":"3"},"values":[[1757941205,"12.5"]]}]

供已有的 Prometheus 或 Grafana 使用。二者都接受 Authorization: Bearer dmt_… 中的 read API 令牌(会话 cookie 也可以);抓取器不发送 X-Requested-With 头,也不需要——这些路由只读。可复制粘贴的 scrape_config 和 Grafana 数据源参见指标参考。

方法路由用途
GET/metrics以 Prometheus 文本展示格式给出实例自身的健康状况:调度器、探测、写入、告警、通知、代理、数据库、VictoriaMetrics。几十条序列,绝不会每个监控项一条。
GET/federate同一格式的测量数据。match[] 选择序列(可重复,最多 10 个,默认为 {__name__=~"dumbmonit_.*"}),max_lookback 放宽查找最后一个点的时间窗口(默认 5m)。超过 8 MiB 时返回 400,并说明应缩小什么。
GET、POST/prometheus/api/v1/{route}Prometheus API 的读取部分,中继到存储,因此 Grafana 可以把 http://…/prometheus 用作 Prometheus 数据源。仅限 query、query_range、query_exemplars、series、labels、label/{name}/values、metadata 和 status/buildinfo;其他任何路由返回 404。

DUMBMONIT_METRICS_PUBLIC=true 会无需令牌地提供这三者——仅限在防火墙之后使用,因为它们包含每个监控项的每一条测量数据。

上文未详述的路由;OpenAPI 文档给出了它们的参数和响应格式。read 和 write 是所需的令牌范围;none 表示不接受任何令牌(仅会话)。

方法路由范围用途
POST/api/targets/reorderwrite重新排序监控项。
GET/api/targets/{id}/securityread一个监控项的安全评分、等级和检查项。
GET/api/security/summaryread每个已评级监控项的安全评分,最差的在前。
GET/api/targets/{id}/webchange/pagesread网站监视所跟踪的页面。
GET/api/targets/{id}/webchange/changesread在被监视网站上发现的变更,最新的在前。
GET/api/targets/{id}/webchange/changes/{change_id}read一次变更,附两个版本及逐行差异。
GET/api/targets/{id}/webchange/snapshots/{snapshot_id}/screenshotread快照的截图。
POST/api/targets/{id}/webchange/checkwrite立即检查被监视的网站。
GET/api/targets/{id}/opnsense/gateways、/traffic、/healthreadOPNsense:网关和 WAN 地址;接口、防火墙和 DHCP;系统、服务、隧道和固件。
GET/api/targets/{id}/truenas/storage、/protection、/healthreadTrueNAS:存储池、数据集和磁盘;清理任务和数据保护任务;系统、告警和服务。
GET/api/targets/{id}/ad、/ad/findingsreadActive Directory:域、控制器、特权组和发现项;原始安全发现。
GET/api/targets/{id}/redfishread从管理控制器读取的服务器硬件信息。
GET/api/targets/{id}/observabilityread日志或指标服务器的健康状况。
GET/api/targets/{id}/backendreadRedis、MongoDB、RabbitMQ 或 CrowdSec 的健康状况。
GET/api/targets/{id}/proxyread反向代理或域名注册的健康状况。
GET/api/public/status/{slug}/badge.svg、/response.svg、/uptime.svgpublic状态页面的整体状态、平均响应时间和可用率徽章。
GET/api/public/status/{slug}/components/{key}/badge.svg、/uptime.svg、/response.svgpublic页面中某一个服务的同样徽章。
GET/api/public/status/{slug}/banner.jspublic供第三方网站使用的状态横幅脚本。
GET/api/public/status/{slug}/rsspublic以 RSS 订阅源形式提供的事故。
GET/api/music/nowread墙面正在播放的内容(房间显示器)。
PUT、DELETE/api/music/linkwrite所有墙面播放此 Spotify、Deezer 或 YouTube 链接;或停止嵌入式播放器。
GET、DELETE/api/music/spotifyread、write已连接的 Spotify 账户(绝不含令牌);断开并忘记其令牌。
POST/api/music/spotify/authorize、/completenone开始连接 Spotify;完成回环连接。仅会话。
GET/api/music/spotify/tokennone供墙面播放器使用的短期 Spotify 访问令牌。仅会话。
GET、PUT/api/music/speakerread、write设置中显示的墙面 Spotify 扬声器;重命名它(管理员)。
POST/api/music/speaker/report、/playnone墙面报告其扬声器的状态;在其上播放该账户。仅会话。
POST/api/music/spotify/playbacknone从墙面暂停或继续该账户的播放,无论在哪里播放。仅会话。
方法路由用途
GET/api/alerts活跃的告警(pending、firing、suppressed、最近已解决)。已删除或已暂停监控项的告警绝不会被列出。
GET/api/alerts/history?since=2026-09-01T00:00:00Z&limit=200&dismissed=false阶段转换。since 为 RFC 3339,默认最近七天;limit 必须为正数。dismissed(默认 false)排除通过下面两个路由清除的条目;清除从不会销毁任何东西,只是在默认视图中隐藏。
POST/api/alerts/history/{id}/dismiss从默认历史视图中清除一条 resolved 条目。204。id 未知或转换仍处于活跃状态时返回 404。操作员;会被审计。
POST/api/alerts/history/dismiss-resolved一次清除所有尚未清除的 resolved 条目(“Clear all resolved”)。返回 {"dismissed": <count>}。操作员;会被审计。
POST/api/alerts/{fingerprint}/ack确认:{"duration_secs": 14400, "note": "…"} 或 {"until": "2026-09-22T18:00:00Z"}(二选一;都不提供则为 4 小时,最长 30 天)。{"until": null} 解除确认。返回该告警。操作员;会被审计。
DELETE/api/alerts/{fingerprint}/ack解除确认。返回该告警。操作员。

一个活跃的告警:

{
"fingerprint": "…",
"rule_uid": "disk_almost_full",
"rule_name": "Disk almost full",
"severity": "warning",
"target_id": 4,
"series_key": "…",
"labels": {"host": "Core switch", "mountpoint": "/", "target": "4"},
"phase": "firing",
"effective_phase": "suppressed",
"suppressed": true,
"suppressed_by": 2,
"silenced": false,
"learning": false,
"acked": true,
"acked_until": "2026-09-15T17:20:00Z",
"acked_by": "admin",
"ack_note": "replacing the disk",
"value": 95.96,
"score": null,
"condition_since": "2026-09-15T12:00:00Z",
"firing_since": "2026-09-15T12:15:00Z",
"last_eval_at": "2026-09-15T13:20:00Z",
"last_notified_at": null,
"notify_count": 0
}

历史条目包含 id、fingerprint、rule_uid、target_id、from_phase、to_phase、severity、value、notified、reason(为空,或说明为何没有发送任何内容:learning: would have fired、suppressed: device 2 unreachable、maintenance window、acknowledged by admin、device removed or disabled)、at 和 dismissed(已从活跃视图中清除;行本身会保留)。只要 acked_until 在未来,acked 就为真:提醒和升级暂停,恢复仍会通知并清除确认。已不存在的 target_id 在 UI 中显示为“(deleted device)”。

方法路由用途
GET/api/alerts/rules每条规则。
POST/api/alerts/rules创建。201。
PUT/api/alerts/rules/{id}更新。内置规则保留其查询。
DELETE/api/alerts/rules/{id}204。内置规则不能删除。
POST/api/alerts/rules/{id}/enable{"enabled": false}。返回该规则。

一条规则:

{
"id": 2, "uid": "cpu_high", "name": "High CPU",
"description": "CPU load sustained above 90%.",
"kind": "threshold",
"query": "avg by (target, host) (dumbmonit_cpu_load_percent or dumbmonit_proxmox_node_cpu_percent or dumbmonit_cpu_usage_percent)",
"operator": ">", "threshold": 90, "for_secs": 600,
"severity": "warning",
"selector": {"kind": "all"},
"channels": [],
"params": {"k": 3.5, "alpha": 0.05, "mad_floor_abs": 1e-6, "mad_floor_rel": 0.01, "min_samples": 3},
"unit": "%", "repeat_secs": 21600, "escalate_after_secs": 3600,
"enabled": true, "builtin": true
}

创建规则至少需要 name 和 query;kind(threshold、anomaly、predict)、operator、threshold、for_secs、severity(info、warning、critical)、selector({"kind":"all"}、{"kind":"ids","ids":[…]} 或 {"kind":"labels","labels":{…}})、channels(渠道 id;为空表示每个已启用的渠道)、unit、repeat_secs、escalate_after_secs 和 enabled 是可选的。

方法路由用途
GET/api/alerts/silences每个窗口,附 active_now、active_until 和 next_start_at(RFC 3339,由服务器计算)。
POST/api/alerts/silences创建。201。操作员。
DELETE/api/alerts/silences/{id}204。操作员。
{
"name": "Sunday backups",
"comment": "NAS is busy",
"target_id": 4,
"matchers": {},
"schedule": {"kind": "weekly", "days": [6], "start_minute": 120, "end_minute": 240, "timezone": "Europe/Paris"},
"enabled": true
}

一次性计划为 {"kind": "once", "starts_at": "2026-09-20T22:00:00Z", "ends_at": "2026-09-21T02:00:00Z"}。每月计划为 {"kind": "monthly", "days": [1], "nth_weekdays": [{"nth": 1, "weekday": 6}], "start_minute": 120, "duration_minutes": 120, "timezone": "Europe/Paris"}——nth 为 1 到 5,或 -1 表示该月最后一次;没有该次数的月份会被跳过。星期的取值为 0 = 星期一 … 6 = 星期日(每月的 days 为 1–31);分钟数为自本地午夜起(0–1439)。对于周期性计划,timezone(IANA 名称)优先于 utc_offset_minutes,并且能让窗口在夏令时变化时仍保持在其本地时刻;未知的时区名称会被拒绝。

可以针对某一个监控项调整规则,而无需改动规则本身。{"enabled": false} 就是 UI 的忽略操作(在告警、监控项页面或规则上)所写入的内容:该监控项被永久(但可逆)地从这一条规则中剔除,而不会对其他任何人禁用该规则。

方法路由用途
GET/api/alerts/overrides?target_id=4每个覆盖,或某个监控项的覆盖:rule_uid、target_id、threshold、clear_threshold、enabled。
GET/api/alerts/rules/{id}/overrides一条规则的覆盖。
PUT/api/alerts/rules/{id}/overrides/{target_id}{"threshold": 95, "clear_threshold": 90, "enabled": true}——每个字段可选;null 表示“与规则相同”。创建或替换。操作员只能发送 {"enabled": false}(忽略);该监控项的阈值覆盖(如果有)会保留。
DELETE/api/alerts/rules/{id}/overrides/{target_id}204。对操作员而言,只解除忽略:阈值覆盖保留。
GET/api/targets/{id}/rulesThe rules that watch a device: those whose query reads a metric it wrote in the last 24 h. {"status": "ok" | "no_data" | "unavailable", "rules": [{id, uid, name, description, severity, enabled, ignored, custom_threshold, firing}]}.
方法路由用途
GET/api/notify/policy全局策略:batch_window_secs(0 = 立即发送)、每个渠道的 max_per_hour(0 = 不限)、flap_events、flap_window_secs、flap_hold_secs(0 = 不检测抖动)、public_url(消息中的链接;为空 = DUMBMONIT_PUBLIC_URL)、escalate_after_secs 和 escalate_channel(0 / null = 不升级)。
PUT/api/notify/policy相同的字段,每个都是可选的:省略的字段保留其值。"escalate_channel": null 关闭升级。返回该策略。
POST/api/notify/match-preview{"matcher": {…}} → 渠道路由过滤器会选中哪些监控项:devices(id、name、kind、tags、matched)、matched、total、rules、excluded_rules。
方法路由用途
GET/api/notify/kinds每种渠道类型及其 settings 和 secrets 字段(key、label、required、input、help、placeholder、options、shape、default),以及 doc_url,例如 https://dumbmonit.selfhostr.io/docs/notifications/#discord。
GET/api/notify/channels每个渠道:id、name、kind、enabled、settings、has_secret、last_error、last_sent_at、policy(min_severity、notify_resolved、min_interval_secs、quiet_hours、matcher)。绝不返回机密。
POST/api/notify/channels创建。201。
PUT/api/notify/channels/{id}更新。省略 secrets 会保留已存储的机密;"secrets": {} 会清除它们。在 policy 中,省略 matcher 会保留路由过滤器,"matcher": null 会清除它。
DELETE/api/notify/channels/{id}204。
POST/api/notify/channels/{id}/test发送测试消息:{"ok": true, "message": "…"}。
{
"name": "Ops Discord",
"kind": "discord",
"enabled": true,
"settings": {"username": "DumbMonit"},
"secrets": {"webhook_url": "https://discord.com/api/webhooks/…"}
}

每种类型的确切键来自 /api/notify/kinds,并记录在通知渠道中。

已登录账户的设备(仅会话,包括查看者;API 令牌会得到 401)。webpush 渠道会向它们发送;参见推送通知(PWA)。

方法路由用途
GET/api/webpush{"public_key": "…", "devices": […]}:VAPID 公钥(base64url,即订阅时使用的 applicationServerKey)以及该账户的设备——id、device(Firefox on Android)、push_service(主机)、fingerprint(端点的 SHA-256 的前 16 个十六进制字符)、created_at、last_success_at、last_error。端点、浏览器密钥和私钥绝不返回。
POST/api/webpush/subscriptionsPushSubscription.toJSON():{"endpoint": "https://…", "keys": {"p256dh": "…", "auth": "…"}}。201 并返回该监控项。端点必须是公共地址上的 HTTPS:私有、回环和链路本地地址会得到 400。同一端点再次提交会替换其行。
DELETE/api/webpush/subscriptions/{id}204;另一个账户的监控项返回 404。
POST/api/webpush/test{} 或 {"id": 3}。发送测试通知:{"ok", "delivered", "failed", "removed", "message"}。返回 404/410 的订阅会被移除。

仅限管理员,包括 GET(响应会列出收件人)。Bearer 令牌进行更改需要 write 范围。参见邮件报告。

方法路由认证用途
GET/api/reports/schedules管理员每个报告:id、name、enabled、frequency、weekday(0 是星期一)、day_of_month、hour、timezone、recipients、channel_id、last_sent_at、last_error、next_run_at。
POST/api/reports/schedules管理员相同的可写字段;各自默认为每周、星期一、8:00、UTC。recipients 最多 20 个地址,启用报告时必填;channel_id 必须是 smtp 渠道或 null。201;超过 10 个报告时返回 409。
GET/api/reports/schedules/{id}管理员一个报告。
PUT/api/reports/schedules/{id}管理员完整替换。
DELETE/api/reports/schedules/{id}管理员204。
POST/api/reports/schedules/{id}/send-test管理员向已保存的收件人发送预览邮件:{"sent": 2, "failed": 0}。不影响计划。没有可用的邮件渠道时返回 400;距上一次预览不足 30 秒时返回 409。
方法路由认证用途
GET/api/status-pages会话每个页面及其条目:page(id、slug、title、description、published、theme、show_uptime_days、created_at、updated_at)和 items(id、page_id、target_id、label、group_name、position)。
POST/api/status-pages管理员{"title", "slug", "description", "published", "theme", "show_uptime_days"}。title 必填(最多 120 个字符);省略 slug(^[a-z0-9-]{2,40}$)时由标题派生;theme 为 auto(默认)、light 或 dark;show_uptime_days 范围 7 到 90(默认 90)。201;slug 已被占用时返回 409。
GET/api/status-pages/{id}会话一个页面及其条目。
PUT/api/status-pages/{id}管理员相同的字段,但是完整替换而不是补丁:title 必填,每个省略的字段都回到默认值(slug 重新由标题派生、描述为空、published: false、theme: auto、90 天可用率)。
DELETE/api/status-pages/{id}管理员204。公开 URL 不再响应。
POST、PUT/api/status-pages、/api/status-pages/{id} — 外观与订阅管理员还接受 accent(default、blue、teal、violet、rose、amber)、scenes(场景 id:paris、tokyo、newyork、dubai,不得重复;已移除的 id 如 venice 或 matterhorn 会归入四者中最接近的一个;[] 表示没有;创建时省略则为 ["paris"])、simple(布尔值,默认 false:公开页面不显示场景、吉祥物或动画,并跟随访客的明暗偏好)、scene_rotation(visit、1m、10m 或 1h)、footer_text(纯文本,280 个字符)、homepage_url(http(s):// 或空)、subscribe_channel_id(一个 smtp 渠道,或 null 以关闭邮件订阅)以及 domain(页面的公开主机名,如 status.example.com,或 null/"" 表示没有——参见自定义域名)。domain 会转为小写并去掉 https:// 前缀或尾部斜杠;带端口、路径或 IP 地址会返回 400,DumbMonit 自身的地址(其公开 URL,或请求进入时使用的主机)返回 400,另一个页面已使用的名称返回 409。与其他字段不同,这八个键在 PUT 中被省略时会保留其存储值。页面视图会连同 logo_type(image/png、image/jpeg、image/webp 或 null)一并返回它们。
GET、PUT、DELETE/api/status-pages/{id}/logo会话 / 管理员页面的徽标。PUT 接受 {"data": "<base64 或 data: URL>"}:按内容识别 PNG、JPEG 或 WebP,最大 256 KiB,其他一切返回 400。204。GET 是编辑器的预览(包括草稿)。
GET/api/status-pages/{id}/subscribers会话邮件订阅者:id、page_id、email、confirmed_at(待确认时为 null)、created_at。其令牌绝不离开服务器。
DELETE/api/status-pages/{id}/subscribers/{subscriber}管理员移除一个地址。204。
PUT/api/status-pages/{id}/items管理员[{"target_id": 4, "label": "NAS", "group_name": "Storage"}, …]——页面上显示的监控项的完整有序列表。
GET/api/incidents会话每个事故及其更新:incident(id、page_id、title、kind、status、severity、starts_at、ends_at、created_at、updated_at)和 updates。
POST/api/incidents管理员{"title", "kind", "status", "severity", "page_id", "starts_at", "ends_at", "body"}——body 是第一条更新。201。
PUT/api/incidents/{id}管理员相同的字段;省略的字段保留其值。
DELETE/api/incidents/{id}管理员204。
GET/api/incidents/{id}/updates会话时间线:id、incident_id、status、body、created_at。
POST/api/incidents/{id}/updates管理员{"status": "monitoring", "body": "…"}。追加一条更新并将事故转为 status。201。
GET/api/public/status/{slug}公开已发布页面所基于的 JSON 文档(同一路径下还有 badge.svg 和 rss)。在 page 中,show_uptime_days 是配置的最大值,history_days 是实际显示的窗口(页面数据的年龄,从 7 天到该最大值),simple 反映简单模式。参见状态页面。在页面的自定义域名上(Host 等于其 domain),只有该页面的 /api/public/status/{slug}/… 路由有响应;本参考中的其他所有路由在那里都返回 404。
GET/api/public/status/{slug}/uptime.svg、/response.svg公开页面徽章:?days= 为 1、7、30(默认)或 90 的平均可用率——超过页面历史范围时返回 400——以及平均响应时间。SVG,Cache-Control: public, max-age=60。
GET/api/public/status/{slug}/components/{key}/badge.svg、/uptime.svg、/response.svg公开某一个服务的同样三个徽章;key 是公开文档中该服务的 key(其标签的 URL 形式)。未知的 key 返回 404。
GET/api/public/status/{slug}/logo公开页面的徽标及其图像类型,可缓存一天(文档的 logo_url 带有版本)。没有徽标时返回 404。
POST/api/public/status/{slug}/subscribe公开{"email": "…"}。通过页面的 SMTP 渠道发送确认链接邮件。无论地址处于何种状态,始终返回 202 和同一条消息;地址无效返回 400;页面不提供邮件订阅时返回 404;页面无法再接受更多订阅者时返回 409;超过每个客户端五次、每 15 分钟总共六十次的请求时返回 429 并带 Retry-After。
POST/api/public/status/{slug}/confirm?token=…公开确认订阅(确认邮件中的链接打开 /s/{slug}/confirm,其按钮向这里 POST)。令牌未知或已过期时返回 404。
POST/api/public/status/{slug}/unsubscribe?token=…公开移除订阅;正文会被忽略,因此它也是 List-Unsubscribe 的 RFC 8058 一键退订目标。始终返回 200。
方法路由认证用途
GET/api/agent/tokens仅会话每个令牌:id、name、prefix、created_at、last_used_at、revoked_at、max_uses(机群令牌为 null)、uses、expires_at。
POST/api/agent/tokens管理员,仅会话{"name": "Home fleet", "base_url": "https://server:8080", "reusable": false, "max_uses": null, "expires_in_days": null}。201,返回令牌字段外加 secret(只显示一次)、install_linux 和 install_windows。base_url 是代理将使用的 URL;默认为监听地址。没有 reusable 时,令牌是一次性的:只注册一台机器,不能再多。有它时,max_uses 限制注册次数(null:无限制)。expires_in_days 在这么多天之后停止注册;已注册的机器继续上报。次数小于 1 时返回 400。
DELETE/api/agent/tokens/{id}管理员,仅会话吊销。204;未知或已吊销时返回 404。
POST/api/ingestAuthorization: Bearer dmon_… + X-DumbMonit-Agent-Secret接收代理发来的一批样本(正文最大 16 MB)。不应手动调用。该头携带机器的绑定密钥;尚无密钥的代理省略它,这就是它请求密钥的方式。响应会增加 agent_secret(密钥,在机器被绑定时仅返回一次)和 bound。当机器被绑定到另一个代理安装,或令牌已无法再注册时返回 403——消息会说明是哪种情况以及该怎么做。
GET/api/agent/relay?wait=NAuthorization: Bearer dmon_… + X-DumbMonit-Agent-Key + X-DumbMonit-Agent-Secret委派给中继代理(relay: true)的探测。没有待处理项时最多保持 wait 秒(最多 25 秒)。每一项都是 probe 类型的命令,其 args 携带目标、其解密后的凭据、timeout_secs 和 discover。绝不写入磁盘。
POST/api/agent/relay/{id}Authorization: Bearer dmon_… + X-DumbMonit-Agent-Key + X-DumbMonit-Agent-Secret被委派探测的结果:{"duration_ms", "error", "samples", "profile_id"}(正文最大 16 MB)。204;探测已过期或属于另一个代理时返回 404。
GET/api/agent/commands?wait=NAuthorization: Bearer dmon_… + X-DumbMonit-Agent-Key + X-DumbMonit-Agent-Secret为代理排队的命令(容器重启或更新),没有待处理项时最多保持 wait 秒。不应手动调用。key 本身说明不了什么——它是公开的——所以已绑定的机器还必须出示其绑定密钥;否则返回 403,这正是阻止一台机器拿走另一台机器命令的机制。
POST/api/agent/commands/{id}Authorization: Bearer dmon_… + X-DumbMonit-Agent-Key + X-DumbMonit-Agent-Secret由代理报告的命令进度和结果。result 被截断为最后 4 KB,发生截断时开头会加上 [truncated by the server, beginning dropped]。
GET/api/relays会话每个可能作为中继的代理监控项:id、name、site、relay(声明了 relay: true)、last_seen_at、relayed(经由它到达的监控项)、gateway_wanted、gateway_port、gateway_host(它为本站点代理提供的网关)、client_id。中继在前,然后按名称排序。
GET/api/relays/kinds会话中继代理可以探测的类型;表单只对这些类型提供经由选项。
{
"id": 1, "name": "Home fleet", "prefix": "dmon_ab12",
"created_at": "2026-09-15 13:00:00", "last_used_at": null, "revoked_at": null,
"secret": "dmon_…",
"install_linux": "curl -sSL https://server:8080/install.sh | sh -s -- --token=dmon_… --url=https://server:8080",
"install_windows": "& ([scriptblock]::Create((irm https://server:8080/install.ps1))) -Token dmon_… -Url https://server:8080"
}

对运行代理的机器上的容器执行操作。当监控项不是 agent 目标时,每个路由都返回 404。

方法路由用途
GET/api/targets/{id}/agent代理最近一次描述的机器:hostname、os、os_version、arch、agent_version、commands_supported、relay、site、relayed(经由此代理到达的监控项)、last_seen_at、binding、bound、bound_at、rebind_until。在代理上报之前返回 404。只有当代理声明它会拉取命令(commands: true,当前代理的默认值)时 commands_supported 才为 true;较旧的代理或 commands: false 的代理为 false。binding 为 bound、pending(该二进制文件可以被绑定,并将在其下一批数据时绑定)或 unsupported(早于绑定功能的代理:请重新安装)。
POST/api/targets/{id}/agent/rebind管理员。开启一个一小时的窗口,在此期间这台机器可以用有效的注册令牌再次绑定自己——这是重新安装带走了代理密钥之后重新进入的途径。{"rebind_until", "minutes"}。窗口一经使用即关闭,旧密钥随即失效。在代理上报之前返回 404。
GET/api/targets/{id}/containers上一批数据中的每个容器:name、image、up、health、restart_count、uptime_seconds、image_age_seconds、update_available、policy、last_command。
PUT/api/targets/{id}/containers/{name}/policy{"auto_restart": bool, "auto_update": bool, "prune_old_image": bool, "only_in_maintenance": bool}。每个字段都是可选的:省略的字段保留其存储值。返回完整的策略。
POST/api/targets/{id}/containers/{name}/restart排队一次重启。201 并返回该命令。name 不在代理的清单中时返回 404;相同命令已在排队或运行,或代理无法运行命令时(见 commands_supported)返回 409。
POST/api/targets/{id}/containers/{name}/update排队一次更新;可选的 {"prune": bool}(默认取自策略)。状态码与重启相同。
GET/api/targets/{id}/commands最近 20 条命令,最新的在前:id、kind(container.restart、container.update)、args、status、requested_by(用户,或 policy)、created_at、started_at、finished_at、result。
DELETE/api/targets/{id}/commands/{command_id}取消一条排队中的命令。204;代理已领取它或它已结束时返回 409;它不属于此监控项时返回 404。

status 依次为 queued → running → done | failed。另有两种最终状态:cancelled(有人撤回了命令)和 expired(服务器在十分钟后放弃,因为没有代理来领取——代理已停止、太旧而不支持命令通道,或以 commands: false 安装)。服务器每分钟自行让过期的命令失效;排队中的命令阻塞新命令的时间绝不会超过这个时长。

Proxmox VE 监控项的客户机面板中的各行,由指标存储中的最近一次探测组装而成(四个即时查询,不向虚拟机管理程序请求任何内容)。监控项不存在时返回 404,不是 proxmox 目标时返回 400。

方法路由用途
GET/api/targets/{id}/proxmox/guests每台 VM 或容器一个对象,按节点再按 VMID 排序:vmid、name、node、kind(qemu、lxc)、status(running、stopped、paused、suspended、template、unknown)、cpu_percent(占分配核心的比例)、cpu_count、memory_used_bytes、memory_total_bytes、memory_percent、balloon_bytes、disk_used_bytes、disk_total_bytes、disk_percent、agent(true 客户机代理已应答,false 已启用但沉默,null 无)、network_in_bps、network_out_bps、disk_read_bps、disk_write_bps、uptime_seconds、last_backup_age_seconds、ha_state、pool(其资源池)、lock(仅在持有锁时:backup、migrate……)、os 和 ip(从客户机内部看到的,每小时刷新)。每个未知值都是 null——没有客户机代理的 VM 有 disk_total_bytes 但 disk_used_bytes: null;已停止的客户机保留其大小,失去其测量值。
[
{
"vmid": 202, "name": "nextcloud", "node": "pve2", "kind": "lxc", "status": "running",
"cpu_percent": 1.0, "cpu_count": 4,
"memory_used_bytes": 1879048192, "memory_total_bytes": 4294967296, "memory_percent": 43.75, "balloon_bytes": null,
"disk_used_bytes": 61203283968, "disk_total_bytes": 107374182400, "disk_percent": 57.0, "agent": null,
"network_in_bps": 1024.0, "network_out_bps": 512.0, "disk_read_bps": 0.0, "disk_write_bps": 2048.0,
"uptime_seconds": 3196800, "last_backup_age_seconds": 25200, "ha_state": "started",
"pool": "production", "lock": null,
"os": "Debian GNU/Linux 12 (bookworm)", "ip": "192.168.10.60"
}
]

同一监控项页面的节点和 Ceph 部分,读取自同一次最近探测。状态码同上。

方法路由用途
GET/api/targets/{id}/proxmox/nodes{"nodes": […], "fencing_state", "fencing_armed"}——HA 看门狗状态(armed、standby……)以及它是否真的会隔离丢失的节点,然后是每个节点一个对象,按名称排序:name、up、cpu_percent、cpu_iowait_percent、memory_percent、ksm_shared_bytes、rootfs_percent、uptime_seconds、version(该节点上安装的 pve-manager 版本)、services_down(已停止或失败的守护进程的单元名称)、interfaces_offline(设置为开机启动但未启用的接口)、thin_pools(name、vg、used_percent、metadata_used_percent、size_bytes)和 volume_groups(name、used_percent、size_bytes)。停止应答的节点保留其条目,up: false。
GET/api/targets/{id}/proxmox/cephavailable(集群没有 Ceph 时为 false——此时 UI 完全不绘制该部分)、health(0 OK、1 WARN、2 ERR、3 未知)、health_status、bytes_used、bytes_total、used_percent、osds_total、osds_up、osds_in、osds(name、host、device_class、up、in、used_percent、used_bytes、total_bytes、apply_latency_ms、commit_latency_ms)、pools(name、used_percent、used_bytes、size、min_size、pg_num、pg_num_optimal、autoscale)、filesystems(CephFS 名称)、flags(当前设置的 OSD 标志,如 noout)和 muted_checks(被静默的健康检查,HEALTH_OK 不再提及它们)。

pbs 监控项的各面板,读取自最近一次探测(除任务日志外不向服务器请求任何内容)。监控项不存在时返回 404,不是 pbs 目标时返回 400。

方法路由用途
GET/api/targets/{id}/pbs/calendar?days=30&offset=120{"probed_at", "days", "offset_minutes", "groups": […]}:每个备份组一项(datastore、namespace、backup_type、backup_id、name、count、last_time、last_size、last_verified、last_success、last_failure、retention),附一个由 {date, state, runs, snapshot} 组成的 days 数组。offset 是查看者相对 UTC 的偏移分钟数,使天数按本地午夜切分。
GET/api/targets/{id}/pbs/failures?days=30失败的任务:upid、worker_type、kind、worker_id、datastore、start、end、error。
GET/api/targets/{id}/pbs/jobs{"probed_at", "jobs": […]}:同步、验证、修剪和垃圾回收任务,附其计划和上次结果。
GET/api/targets/{id}/pbs/health数据存储(使用率、预计占满日期)、磁盘(SMART、磨损度)和 ZFS 池。
GET/api/targets/{id}/pbs/tasks/{upid}/log?lines=200一个任务的日志,从服务器获取:{"upid", "lines": […]};lines 限制返回的行数。
GET/api/targets/{id}/pbs/disks/smart?disk=/dev/sda一块磁盘的 SMART 属性;disk 必填(缺少时返回 400)。
GET/api/targets/{id}/pdm/remotesProxmox Datacenter Manager:整体规模总计(estate)以及每个联邦实例一行(id、kind、reachable、error、version、version_behind、节点和客户机数量、内存和存储、subscription、last_collection、tasks_failed),不可达的在前。
GET/api/targets/{id}/pdm/failures?days=14整个规模中失败的任务:upid、remote、worker_type、kind、worker_id、node、start、end、error。
GET/api/targets/{id}/pdm/health控制台主机:CPU、内存、根文件系统、运行时间、证书、待处理更新和订阅。
GET/api/targets/{id}/pmg/queuesProxmox Mail Gateway:按阅读顺序排列的四个 Postfix 队列(queue、messages、domains、oldest_age_seconds、top_domains、stuck),外加 total_messages 和网关范围的 stuck。oldest_age_seconds 是下界:qshape 报告的是年龄区间。
GET/api/targets/{id}/pmg/traffic今日总计(mail)、近期流量曲线(recent)、垃圾邮件评分直方图、今日拦截的病毒,以及隔离区计数(quarantine)。仅有计数:不含邮件内容。
GET/api/targets/{id}/pmg/health每个节点一项(系统、服务、带 family、age_seconds 和 stale 的 signatures、expiring_certificates、更新、订阅),带同步状态的 cluster 成员,以及跨节点的 stopped_services。
方法路由用途
GET/api/targets/{id}/synology来自最近一次探测的 synology 监控项概览:system(型号、DSM 版本、运行时间、温度、CPU、内存)、volumes(name、fs_type、raid_type、status、severity、total_bytes、used_bytes)、disks(model、serial、kind、ssd、status、smart_status、temperature_celsius、size_bytes、remaining_life_percent、……)和 sampled_at。监控项不存在时返回 404,不是 Synology 时返回 400。
GET/api/targets/{id}/synology/abbActive Backup for Business:tasks,以及 devices——每台受保护设备一份报告,其学习到的节奏在 assessment 中(state、last_success_s、typical_interval_s、30 天计数)。
方法路由认证用途
GET 或 POST/api/push/{token}无(令牌即认证)任务每次运行时发起的调用。可选的 ?status=up|down&msg=…(兼容 Uptime Kuma)。成功时返回空的 204,令牌未知返回 404,其他 status 返回 400,每个令牌每分钟超过六十次调用返回 429 并带 Retry-After。参见心跳。
GET/api/targets/{id}/push会话push 监控项的监控:token、path(/api/push/<token>)、last_seen_at、last_seen_age_secs、last_status、last_message、received_total、expected_interval_secs、grace_secs、settings_error、verdict(waiting、on_time、missed、reported_down)。首次读取时创建。监控项不是心跳监控项时返回 400。
POST/api/targets/{id}/push/regenerate管理员新令牌;此后旧 URL 返回 404。正文与读取相同。

内置的 Model Context Protocol 服务器,即助手与之通信的那一个。它使用上述 API 令牌认证——相同的范围、有效期、网络和速率限制——绝不使用会话。

方法路由认证用途
POST/api/mcpAPI 令牌基于 Streamable HTTP 传输的 JSON-RPC 2.0,每个 POST 一个请求,以 JSON 应答。协议 2026-07-28(无状态:每个请求在 _meta 中携带其版本和客户端能力,外加 MCP-Protocol-Version、Mcp-Method 和 Mcp-Name 头;server/discover),以及通过 initialize 握手的 2025-11-25、2025-06-18 和 2025-03-26。没有会话:不颁发 Mcp-Session-Id,发送的会被忽略。通知得到 202 且没有正文。
GET、DELETE/api/mcp公开返回 405 并带 Allow: POST——没有服务器发送的流,也没有可结束的会话;正文只说明此端点是什么。

tools 是唯一的能力——没有资源、没有提示词、没有 OAuth。在 27 个工具中,read 令牌可以调用其中 15 个只读工具(get_status、list_devices、get_device、list_alerts、alert_history、query_metrics、list_silences、list_rules、list_device_types、list_agents、list_containers、list_heartbeats、list_status_pages、list_channels、list_packs);会更改内容的 12 个(silence_device、remove_silence、acknowledge_alert、probe_device、set_device_enabled、set_rule_enabled、add_device、discover_network、schedule_maintenance、restart_container、test_channel、post_incident)需要 write 令牌。这些工具调用与 Web UI 相同的代码。版本、头、错误代码和安全说明见连接助手。

方法路由用途
GET/install.shLinux、macOS 和 FreeBSD 安装程序。公开。
GET/install.ps1Windows 安装程序。公开。
GET/download/{name}dumbmonit-agent-linux-x86_64、dumbmonit-agent-linux-aarch64、dumbmonit-agent-freebsd-x86_64、dumbmonit-agent-windows-x86_64.exe,由 DUMBMONIT_AGENT_DIR 提供;{name}.sha256 以 sha256sum 格式给出其校验和。文件不存在时返回 404。dumbmonit-agent-macos-aarch64 和 dumbmonit-agent-macos-x86_64(及其 .sha256)以 307 重定向到最新 GitHub 发布版本上的同一文件。公开。

其他所有路径都由 Web UI 提供,它会自行要求你登录。