ServerStatus (cppla) review: a Go server probe with a web panel and HTTP API
Cloud probe and multi-server monitoring tool for cloud servers. Demo: https://tz.cloudcpp.com/
At a glance
- What is it?
- ServerStatus is a lightweight multi-node probe and monitoring panel written in Go, with a Python client, a JSON config file, and an authenticated HTTP API. It fits small fleets that want one dashboard without a metrics stack.
- Who is it for?
- Adopt ServerStatus if you run a handful of VPS or dedicated nodes and want status, latency and traffic in one panel without operating Prometheus and Grafana. Skip it if you need long-term time-series retention, per-metric alerting or a hosted service, since the README documents only a current-state snapshot, Watchdog rules and callbacks.
- 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 11 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 November 14, 2026, and from our analysis. They are not legal advice.
Star history
- cppla/ServerStatus4,682 ★ · -11
| Repository | 2026-09-23 | 2026-11-14 |
|---|---|---|
| cppla/ServerStatus | 4.7k | 4.7k |
-11 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
What ServerStatus solves, and for whom
The project describes itself as a lightweight server probe and cloud monitoring panel. The scope is deliberately narrow: online status per node, resource usage, three-carrier latency, service checks, SSL certificate checks, Watchdog alerting, an HTTP API and a web configuration page. The demo instance at tz.cloudcpp.com shows the intended output.
The audience is the operator of a small fleet. If you run a few VPS instances across providers and want one page that answers "is node3 up, how much traffic has it used this month, and is its certificate close to expiry", this covers that without a time-series database. It is a worse fit for anything that needs per-metric history or query languages. The README documents a stats.json persistence file, not a metrics store, and that distinction decides most adoption questions.
How the agent, server and WebUI fit together
The architecture is a push model with three parts. A client agent runs on each monitored host, the Go server listens for reports, and a static WebUI reads a JSON snapshot from the same server. The default agent TCP port is 35601, and the client table lists PORT with that default, so the server's AGENT_ADDR and the client's PORT must agree.
The client samples the host and sends status over TCP at INTERVAL seconds, default 1. The server keeps the latest state and writes stats.json every 60 seconds, plus immediately on key operations and clean shutdown. The WebUI does not query agents directly; it reads /json/stats.json, which is the same live snapshot the panel renders.
Two client implementations exist. CLIENT defaults to psutil, and linux is the alternative. The shell run example downloads clients/client-linux.py and starts it with python3, so the Python client is the one the README leads with. Latency probing is separate from status reporting: the client probes a TCP port, PROBEPORT default 80, against three carrier addresses, CU, CT and CM, with PROBE_PROTOCOL_PREFER choosing ipv4 or ipv6. Those carrier defaults point at the author's tz.cloudcpp.com hosts, which is worth checking before you rely on the numbers.
Installing the server with Docker and reading the first health check
The README gives Docker Compose and Docker Run paths. The Compose form is one line, and the server image is cppla/serverstatus:server. ADMIN_TOKEN is passed as an environment variable at startup.
ADMIN_TOKEN='your-strong-token' docker compose -f docker-compose-server.yml up -dThe Docker Run path is more explicit and shows what gets mounted. It fetches server/config.json from the repository with the GitHub raw media type, creates a data directory, then mounts the config as a single file and the data directory as a volume. Ports 8080 and 35601 are published, mapping the container's HTTP port 80 and the agent port.
wget -qO ~/serverstatus-config.json \
--header='Accept: application/vnd.github.raw' \
'https://api.github.com/repos/cppla/ServerStatus/contents/server/config.json?ref=master'
mkdir -p ~/serverstatus-data
docker run -d --restart=always --name=serverstatus-server \
-e ADMIN_TOKEN='your-strong-token' \
-v ~/serverstatus-config.json:/app/config/config.json \
-v ~/serverstatus-data:/app/data \
-p 8080:80 -p 35601:35601 \
cppla/serverstatus:serverAfter startup the README lists four endpoints to open: the WebUI at http://127.0.0.1:8080/, the health check at /api/health, the machine-readable description at /api/schema, and OpenAPI 3.1 at /api/openapi.json. The health endpoint reports process, agent TCP, version and config path status, so it is the first thing to curl. If ADMIN_TOKEN is unset, the monitoring page still reads, the management API returns 503, and the configuration page in the WebUI cannot change data. Set the token at container start rather than adding it later.
Starting a client and watching the node appear
The client is a separate container or process. The Docker Run form uses host networking and host PID namespace, which is what lets it see host-level resource data, and passes SERVER, USER and PASSWORD. The default password constant in the README is USER_DEFAULT_PASSWORD.
docker run -d --restart=always --name=serverstatus-client \
--network=host --pid=host \
-e SERVER=127.0.0.1 \
-e USER=s01 \
-e PASSWORD=USER_DEFAULT_PASSWORD \
cppla/serverstatus:clientThere is a documented trap here. USER is a common host environment variable, and the README warns that if it is not passed explicitly or is passed incorrectly, Compose may resolve the system $USER to the local username instead of s01. The stated priority order is an explicit USER=s01 on the command line, then editing the default in docker-compose-client.yml, then the Docker or system environment. The server side has a matching constraint: servers.username must be unique in config.json, and the client username and password must match the server entry.
For a host without Docker, the README downloads the Python client and runs it under nohup with the same three variables.
wget -qO client-linux.py --header='Accept: application/vnd.github.raw' \
'https://api.github.com/repos/cppla/ServerStatus/contents/clients/client-linux.py?ref=master'
nohup python3 client-linux.py SERVER=127.0.0.1 USER=s01 PASSWORD=USER_DEFAULT_PASSWORD >/dev/null 2>&1 &Managing nodes through the API instead of editing JSON
The management API is the part that distinguishes this from a static probe script. It uses a Bearer token, and the README splits the endpoints into unauthenticated and authenticated sets. Health, schema, the OpenAPI document and /json/stats.json need no token. Config, servers, monitors, sslcerts, watchdog, reload and restart all do.
TOKEN='replace with ADMIN_TOKEN'
curl -H "Authorization: Bearer ${TOKEN}" \
http://127.0.0.1:8080/api/config
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 request body is capped at 1 MiB. Configuration changes follow a validate, back up, persist, atomic switch order. On success, existing agent connections are closed, and the README states the Python client reconnects after about 3 seconds and picks up the new monitors list. That reconnect window is the cost of live config changes, and it means a config edit is not invisible to agents.
POST /api/restart restarts the collection runtime inside the process rather than exiting the Go process, so Docker and manual runs behave the same way. The OpenAPI 3.1 document at /api/openapi.json is described as importable by an AI agent, and a lighter client can read /api/schema first and then call the CRUD endpoints for the collections it lists. That is a real integration path, not just documentation.
Watchdog rules, certificate checks and their limits
Watchdog entries carry a rule, an interval and a callback. Rules run through the Go expr engine and accept the older Exprtk style, with automatic conversion of a single operator outside strings: & to &&, | to ||, and = to ==. The README shows two equivalent forms, cpu>90&load_1>5&username!='s01' and the same expression with doubled operators. String values support Chinese, Emoji and other Unicode.
One detail is easy to misread. For Watchdog, interval is the notification cooldown, not the client collection interval. The general config constraint says interval has a minimum of 1 second, and the monitors example uses 600, but in Watchdog the value means notification cooldown.
SSL certificate entries take a domain, a port clamped to 1-65535, an interval and a callback. Both watchdog and certificate callbacks can be told to accept untrusted TLS through INSECURE_CALLBACK_TLS, which defaults to false.
Where ServerStatus is the wrong tool
The persistence model is the main boundary. stats.json holds monthly traffic and status, written every 60 seconds. There is no documented retention window, no downsampling and no query interface over history. If you need to answer what latency looked like last Tuesday at 03:00, this is not the system for that, and adding it would mean scraping /json/stats.json into something else on your own schedule.
Configuration backups are also weaker than they look in a container. A config write creates config.json.bak-* files and keeps at most 10. But with a single-file bind mount, the README states those backups land in the container's writable layer at /app/config, and it recommends backing up server/config.json on the host as well if you want to keep version history. A container rebuild can take those backups with it.
Finally, the carrier latency defaults point at the author's own probe hosts. They are overridable through CU, CT and CM, but if you never change them you are measuring paths to a third party's infrastructure, which may not reflect what your users experience.
Compared with a Prometheus and Grafana stack
The obvious alternative for multi-node monitoring is Prometheus with node_exporter and Grafana. The difference is architectural, not cosmetic. Prometheus pulls metrics from exporters on a scrape interval and stores them in a time-series database, so you get retention, PromQL queries, recording rules and per-metric alerting through Alertmanager. Grafana renders that history and lets you build arbitrary dashboards.
ServerStatus pushes a current-state report to one server and renders a fixed panel. There is no query language, no retention policy to tune, and no per-metric alert expression beyond the Watchdog rule string. What you get in exchange is a single Go binary plus a client, a JSON config file, and no database to operate. For five nodes and a person who wants one page, that trade is reasonable. For fifty nodes with an on-call rotation and service-level objectives, the absence of history and per-metric alerting is disqualifying.
The README describes a Go server with an HTTP management API, OpenAPI output, certificate checks and a WebUI config page, which is a different surface from a minimal probe. If you only need the panel and never the API, the extra endpoints are surface area you are still running.
Maintenance, licence and upgrade cost
The repository is not archived, and the last push was on 2026-08-20. Recent releases are 2.0.1 on 2026-08-10, 2.0.0 on 2026-07-10 and 1.1.9 on 2026-07-09, so the release cadence over the past two months has been active. A CI workflow exists at .github/workflows/ci.yml.
The licence is MIT, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. That is the standard reading of the identifier in the repository; it is not legal advice, and if you redistribute a modified build you should read the LICENSE file in the repository root yourself.
Upgrade cost depends on how you deployed. With Docker, your config and data live in the two mounted paths, so they survive. The risk sits in config compatibility across versions; the README notes that old --bind/-b and --port/-p flags still work for the agent listen address, which suggests deliberate backward compatibility. Keep the host-side copy of server/config.json before you upgrade.
Editorial conclusion
Adopt ServerStatus if you run a handful of VPS or dedicated nodes and want status, latency and traffic in one panel without operating Prometheus and Grafana. Skip it if you need long-term time-series retention, per-metric alerting or a hosted service, since the README documents only a current-state snapshot, Watchdog rules and callbacks. Before deploying, verify the ADMIN_TOKEN behaviour: without it the monitoring page stays readable but the management API returns 503, and confirm your client USER and PASSWORD match the server config, because the client USER variable can be shadowed by the host environment.
Frequently asked questions
What does ServerStatus actually monitor?
The README lists multi-node online status, resource usage, three-carrier latency, service monitoring, SSL certificate checks, Watchdog alerting, an HTTP API and web configuration management. It is a current-state panel rather than a historical metrics store.
How do I install the ServerStatus server?
The README gives two Docker paths: a one-line docker compose -f docker-compose-server.yml up -d with ADMIN_TOKEN set, or a docker run of cppla/serverstatus:server with the config file and data directory mounted and ports 8080 and 35601 published.
Which port does the ServerStatus client report to?
The agent TCP reporting port defaults to 35601, set by PORT on the client and AGENT_ADDR on the server. The Docker Run example publishes 35601 alongside the HTTP port.
What happens if ADMIN_TOKEN is not set?
According to the README, the monitoring page remains readable, the management API returns 503, and the configuration page in the WebUI cannot modify data.
Official sources
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.
[](https://hysenlabs.com/projects/cppla-serverstatus)Star history chart for your README
[](https://hysenlabs.com/projects/cppla-serverstatus)Was this useful?