Server protocol

Set up a server

Kumo Tabs never logs into your servers or installs anything on them. Each server answers one small HTTP request with a JSON report that you write yourself, in any language.

In a hurry? Copy a ready-made endpoint from the examples: PHP, Laravel, a WordPress plugin, a PrestaShop module, Node.js, Bun, Python, Go, Rust, C#, Ruby, Java…

Steps

  1. Pick an address for the endpoint, for example https://example.com/vitals. Any path works.
  2. In Kumo Tabs, open Settings → Servers → Add a server, fill in the name and the address, then press Generate. The token stays in your browser.
  3. Copy the Token hash (SHA-256) shown under the token, and store it on the server, in an environment variable or a config file. The server never needs the token itself.
  4. Write the endpoint described below, and deploy it.
  5. Back in Kumo Tabs, press Save & check and allow access to that host when the browser asks. The card turns green when the report arrives.

The request

Kumo Tabs sends:

GET /vitals HTTP/1.1
Host: example.com
X-Vitals-Token: <the token>
Accept: application/json

The endpoint hashes the header with SHA-256, compares it with the stored hash, then answers:

Situation Answer Kumo Tabs shows
No hash configured on the server 404 Down
Missing or wrong token 401 Bad token
Right token 200 with the JSON report Up or Degraded
Anything else, timeout, non-JSON - Down

?fresh=1 is added when the user presses ⟳ Check now: if your endpoint caches parts of its report, rebuild them for that request.

No CORS headers are needed: the extension calls your server with the host access the user granted.

Test it from a terminal

The token’s hash, to compare with the one shown in Kumo Tabs:

printf '%s' 'the-token' | sha256sum

The request itself:

curl -i -H 'X-Vitals-Token: the-token' https://example.com/vitals

The report

The smallest valid report is:

{ "ok": true }

Every other section is optional: send the ones you can, and the card shows what it gets. A complete report looks like this:

{
  "ok": true,
  "app": { "name": "My app", "build": 1792288695, "branch": "main", "commit": "b80995c" },
  "php": { "version": "8.5.12", "sapi": "fpm-fcgi", "opcache": true },
  "db": { "ok": true, "version": "10.11.6-MariaDB", "latencyMs": 1.4 },
  "server": {
    "software": "Apache/2.4.58 (Ubuntu)",
    "os": "Linux 6.8.0-85-generic",
    "uptime": 1224600,
    "load": [0.42, 0.37, 0.31],
    "cpus": 4,
    "memory": { "total": 8589934592, "free": 3328599654 },
    "disk": { "total": 171798691840, "free": 76235669504 }
  },
  "crons": {
    "counts": { "ok": 28, "idle": 3, "late": 1 },
    "failing": [{ "name": "cleanSessions", "status": "late" }]
  },
  "dependencies": [
    { "name": "PHP", "group": "runtime", "version": "8.5.12" },
    { "name": "MariaDB", "group": "database", "version": "10.11.6" },
    { "name": "smarty", "group": "php", "version": "5.8.5", "package": "smarty/smarty" },
    { "name": "chart.js", "group": "npm", "version": "4.5.1", "package": "chart.js", "wanted": "^4.5.1", "dev": false }
  ],
  "cache": { "stack": { "at": 1792288000, "ttl": 3600 } }
}

ok (required)

true when the endpoint could build its report. Anything else counts as Down; an optional error string is shown on the card.

app

Field Type Shown as
name string Application name
build string or number Build or release number
branch, commit string branch@commit

php

Field Type Shown as
version string Also shown in compact mode
sapi string e.g. fpm-fcgi
opcache boolean Adds “opcache” when true

Other runtimes (Node.js, Python, Go…) go in dependencies with "group": "runtime".

db

Field Type Shown as
ok boolean false marks the server Degraded
version string As the database reports it (SELECT VERSION())
latencyMs number Time of a trivial query

server

Field Type Shown as
software, os string Web server and operating system
uptime number Seconds
load number[3] 1, 5 and 15-minute load averages
cpus number CPU count, compared with the 5-minute load
memory, disk { total, free } Bytes, drawn as usage bars

crons

Field Type Shown as
counts object Number of jobs per status, one chip each. ok, idle, running, late, failed and stuck get their own colours
failing { name, status }[] Jobs that need attention; any entry marks the server Degraded

dependencies

A list of the software your server runs, grouped on the card and checked for updates.

Field Type Meaning
name string Display name; also picks the release source (below)
group string runtime, database, server, system, php or npm
version string Installed version
package string Packagist or npm package name, for update checks
wanted string Constraint from package.json, e.g. ^4.5.1
dev boolean Development dependency (can be hidden in the settings)

cache

If your endpoint caches its slow parts, cache.stack.at (Unix seconds) tells the card how old the versions are.

Health

State When
Up 200, "ok": true and none of the issues below
Degraded db.ok is false, crons.failing is not empty, disk or memory has less than 10% free, or the 5-minute load is above cpus
Down Network error, timeout, non-JSON answer, any status other than 200 or 401
Bad token 401

The response time is measured by Kumo Tabs; you do not need to send it.

Update checks

Each dependency is compared with its official releases, picked by name or package:

Dependency Source
name is PHP, Node.js, Bun, MySQL, MariaDB, Apache, nginx or OpenSSL (spelled exactly so) endoflife.date: end of life, LTS and supported branches
group: "php" with a package Packagist, stable tags
Any other package npm
No match Listed without a badge

Security

  • Serve the endpoint over HTTPS, so the token never travels in clear text.
  • Store only the SHA-256 hash, and compare it in constant time (hash_equals in PHP, crypto.timingSafeEqual in Node.js, hmac.compare_digest in Python, subtle.ConstantTimeCompare in Go).
  • Answer 404 while no hash is configured, so an unconfigured endpoint reveals nothing.
  • Report versions and states only: never paths, environment variables, keys or user data.
  • Cache slow parts (version commands, cron history) for a few minutes; Kumo Tabs calls every 60 seconds by default.
  • To revoke access, generate a new token and replace the stored hash.