Self-hosted service
cppla/ServerStatus avatar
cppla/ServerStatus

ServerStatus: a Go probe panel with its admin API laid out for AI agents

云探针、多服务器探针、云监控、多服务器云监控,演示: https://tz.cloudcpp.com/

4,694 stars925 forksGoMIT

At a glance

What is it?
ServerStatus is cppla's lightweight server probe and cloud monitoring panel written in Go, tracking multi-node online status, resource usage, latency against China's three carrier networks, service monitors, SSL certificate checks and Watchdog alerting, with an HTTP API documented in OpenAPI 3.1. A live demo runs at tz.cloudcpp.com and the current release is 2.0.1.
Who is it for?
Deploy ServerStatus when you run a handful of machines or VPS nodes and want one small panel showing online status, resources, carrier latency and certificate expiry, managed either through the WebUI or scripts against its Bearer token API. Skip it if you need a monitoring stack with long historical storage or alert routing beyond Watchdog callbacks, this is a probe panel, not a time series platform.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 41 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One Go binary's worth of panel, five jobs inside

ServerStatus describes itself as a lightweight server probe and cloud monitoring panel, and the feature list is long for something lightweight, multi-node online status, resource usage, latency probes against the three major Chinese carrier networks, service monitoring, SSL certificate checks, Watchdog alerting, an HTTP API, and web-based configuration management. A public demo runs at tz.cloudcpp.com. The server side is Go, the web UI is static files it serves, and the repository carries Dockerfile.server and Dockerfile.client plus compose files for each role. Development is brisk, 2.0.1 released 2026-08-10, 2.0.0 on 2026-07-10 and 1.1.9 on 2026-07-09, with the last push on 2026-08-20. The license is MIT. There is even a Playwright suite, a package.json named serverstatus-webui-tests pinned to pnpm and @playwright/test 1.62.1 with a test:webui script, covering the web UI end to end.

Two ports: 8080 for people, 35601 for agents

The server starts as one container. With Compose it is

code
ADMIN_TOKEN='your-strong-token' docker compose -f docker-compose-server.yml up -d

and with plain Docker it fetches the stock config.json from the GitHub contents API, creates a data directory, and runs cppla/serverstatus:server with the config and data volumes bound and ports 8080 and 35601 published. After startup four surfaces exist, the WebUI at the root, a health check at /api/health, an endpoint description at /api/schema, and a full OpenAPI 3.1 document at /api/openapi.json, while clients report into port 35601 over TCP. ADMIN_TOKEN is the single switch for the management surface, and its failure mode is worth knowing, when it is not set, the monitoring page remains readable, the management API returns 503, and the configuration page in the WebUI cannot modify data. The panel degrades to read only rather than to open.

The USER variable bites Compose deployments

Client deployment comes in three flavors. Compose runs SERVER=127.0.0.1 USER=s01 PASSWORD=USER_DEFAULT_PASSWORD before docker compose -f docker-compose-client.yml up -d --force-recreate. Docker proper runs cppla/serverstatus:client with --network=host and --pid=host and the same three variables. And a minimal shell path downloads client-linux.py from the repository through the GitHub contents API and runs it under nohup with the credentials as arguments. The README spends real effort on one trap, USER is a common host environment variable name, so if it is not passed explicitly or is passed incorrectly, Compose can resolve the system's $USER to the local machine's username instead of the intended default s01. The recommended priority is explicit USER=s01 in the run command first, editing the compose file's default second, and relying on Docker or system environment only as the last resort.

The client's dials: probe ports and carrier targets

The client's environment table is where its behavior lives. SERVER points at the Go server, USER and PASSWORD must match the server configuration, and PORT defaults to 35601 for the agent TCP connection. INTERVAL sets the status reporting interval in seconds and defaults to 1. The triple-network probing is configurable too, PROBEPORT defaults to 80 as the TCP probe port for the three carrier targets, PROBE_PROTOCOL_PREFER picks ipv4 or ipv6, and PING_PACKET_HISTORY_LEN sets the packet loss history window at 100. The three probe endpoints themselves default to cu.tz.cloudcpp.com, ct.tz.cloudcpp.com and cm.tz.cloudcpp.com, matching Unicom, Telecom and Mobile, so latency per carrier is measured against fixed reference hosts rather than the monitored server's own address. Finally CLIENT selects the implementation, psutil or linux, choosing between the Python dependency version and the native one.

stats.json every 60 seconds, written back in place

The server's environment covers paths and listeners. CONFIG_PATH defaults to /app/config/config.json, WEB_DIR to /app/web for the static UI, HTTP_ADDR to :80 for the WebUI and HTTP API, and AGENT_ADDR to :35601 for client reporting. STATS_PATH points at /app/data/stats.json, the persistence file for monthly traffic and state, written every 60 seconds and immediately on critical operations and clean exit, so restarts lose at most a minute of counters. INSECURE_CALLBACK_TLS defaults to false and gates whether Watchdog and certificate callbacks may use untrusted TLS certificates, VERBOSE turns on Gin HTTP request logs, and TZ defaults to Asia/Shanghai for the container. Every setting has a command line twin, --config and -c, --stats, --web-dir and -d, --http, --agent, --verbose and -v, plus --version, and the legacy --bind and --port flags still work to set the agent TCP listener.

An admin API built to be imported, not scraped

Management requests authenticate with a Bearer token in the Authorization header. Four routes need no token, /api/health for process, agent TCP, version and config path status, /api/schema for a machine readable description of endpoints and configuration collections, /api/openapi.json for the OpenAPI 3.1 document, and /json/stats.json for the real time snapshot the WebUI itself consumes. The authenticated surface is a full CRUD set, GET and PUT on /api/config, listing and creating nodes under /api/servers with per-node modification and deletion by username, a reset-traffic action that sets current traffic as the monthly baseline, the same three verbs for monitors, sslcerts and watchdog entries addressed by index or name, plus /api/reload to re-read config from disk and /api/restart to restart the collection runtime in place. Request bodies cap at 1 MiB. Creating a node is one call:

code
curl -X POST http://127.0.0.1:8080/api/servers \
  -H "Authorization: Bearer ${TOKEN}" \
  -H 'Content-Type: application/json' \
  -d '{"username":"s05","name":"node5","type":"kvm","host":"host5","location":"SG","password":"change-me","monthstart":1}'

The README states the intent plainly, AI agents can import the OpenAPI document directly, and lighter clients can read the schema first and drive the CRUD endpoints from it.

Validate, backup, persist, atomic switch

Configuration changes run a fixed pipeline, validation first, then a backup, then persistence, then an atomic switch to the new configuration. On success, existing agent connections are closed, and the Python client reconnects automatically after roughly three seconds and picks up the new monitors. The restart endpoint never exits the Go process, restarting only the collection runtime in place, which gives Docker and manual runs the same semantics. Backups rotate as config.json.bak files with at most ten kept. One container detail is handled explicitly, when config.json is bind mounted as a single file, rename cannot overwrite it, so the server safely writes back to the original inode after completing the backup, and the README adds the operational corollary, those backups then live in the container's /app/config writable layer, so anyone wanting long term history should also copy server/config.json on the host.

Watchdog rules run through Go expr with operator mercy

Watchdog rules are expressions executed by the Go expr engine, kept compatible with the common syntax of the older Exprtk engine. Single operators outside strings are converted automatically:

code
&  -> &&
|  -> ||
=  -> ==

so the terse and the explicit forms mean the same thing:

code
cpu>90&load_1>5&username!='s01'
cpu>90 && load_1>5 && username!='s01'

String values may contain Chinese, emoji and other Unicode, while field names must use the system defined English names. The field list is long and concrete, username, name, type, host, location, the three load averages, cpu, memory and swap totals and used, disk totals and used, network receive and transmit rates, the three carrier ping values and probe times, tcp, udp, process and thread counts, io read and write, and the online4 and online6 flags. Interval inside a Watchdog means notification cooldown, not the client collection interval. Offline rules are only evaluated after a client has been disconnected for 25 seconds without reconnecting, which keeps transient drops from firing alerts.

Editorial conclusion

Deploy ServerStatus when you run a handful of machines or VPS nodes and want one small panel showing online status, resources, carrier latency and certificate expiry, managed either through the WebUI or scripts against its Bearer token API. Skip it if you need a monitoring stack with long historical storage or alert routing beyond Watchdog callbacks, this is a probe panel, not a time series platform. Before deploying, set ADMIN_TOKEN to unlock the management API at all, remember the unset state returns 503 on admin routes, and if you mount config.json as a single file into Docker, copy backups off the container writable layer since only ten rotating .bak files live there.

Frequently asked questions

What is ServerStatus?

ServerStatus is a lightweight server probe and cloud monitoring panel written in Go by cppla, covering multi-node online status, resource usage, latency against China's three carrier networks, service monitoring, SSL certificate checks, Watchdog alerting, an HTTP API and web configuration management. A demo runs at tz.cloudcpp.com and it is MIT licensed.

How is the ServerStatus client configured?

The client takes SERVER, USER and PASSWORD, which must match the server configuration, plus PORT defaulting to 35601, INTERVAL in seconds for reporting, PROBEPORT and PROBE_PROTOCOL_PREFER for the carrier probes, and CLIENT choosing the psutil or linux implementation. It runs via Docker Compose, plain Docker with host networking, or a standalone client-linux.py script under Python 3.

What happens when ServerStatus has no ADMIN_TOKEN set?

The monitoring page remains readable, the management API returns 503, and the configuration page in the WebUI cannot modify data. Setting ADMIN_TOKEN enables the Bearer token authenticated management endpoints.

Official sources

  1. cppla/ServerStatus on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/cppla-serverstatus.svg)](https://hysenlabs.com/projects/cppla-serverstatus)