GitHub - wojtczyk/serverload2: Sometimes all you want is a simple self-contained load monitor for your server.

3 min read Original article ↗

About

Sometimes all you want is a simple self-contained load monitor for your dedicated server or home server.

server load is a small, self-contained Linux load monitor written in Rust. It provides a typed JSON API and a responsive browser dashboard with live load averages, uptime, CPU capacity, and a rolling in-memory history served to every browser.

The service is designed to listen on loopback while Apache provides the public URL, optional HTTPS, and optional authentication.

iPhone Desktop
ServerLoad dashboard on iPhone ServerLoad dashboard on desktop

API

GET /api/v1/load returns:

{
  "schema_version": 1,
  "sampled_at": "2026-07-16T12:00:00Z",
  "load_average": {
    "one_minute": 0.12,
    "five_minutes": 0.18,
    "fifteen_minutes": 0.21
  },
  "uptime_seconds": 5097600,
  "logical_cpu_count": 4
}

GET /healthz checks the latest in-memory metrics sample. API responses are never cached by clients. ServerLoad intentionally does not provide JSONP or permissive CORS headers.

GET /api/v1/load/history returns retained samples from oldest to newest in pages of up to 5,000. Pass the opaque next_cursor back as GET /api/v1/load/history?cursor=... to retrieve only newer samples. A 410 Gone response means the cursor expired or belongs to a previous server process and the client must bootstrap again without a cursor.

{
  "schema_version": 1,
  "cache_id": "825e2d47-4657-4e16-a61c-78f69283850f",
  "retention_hours": 24,
  "sample_interval_seconds": 3,
  "oldest_sequence": 1,
  "collection_status": "ok",
  "samples": [
    {
      "sequence": 1,
      "sampled_at": "2026-07-16T12:00:00Z",
      "load_average": {
        "one_minute": 0.12,
        "five_minutes": 0.18,
        "fifteen_minutes": 0.21
      },
      "uptime_seconds": 5097600,
      "logical_cpu_count": 4
    }
  ],
  "next_cursor": "opaque-value",
  "has_more": false
}

Build and run

ServerLoad targets Linux and reads /proc/loadavg and /proc/uptime directly.

cargo build --release
./target/release/serverload

The default listen address is 127.0.0.1:9180. Override it with either:

serverload --listen 127.0.0.1:9200
SERVERLOAD_LISTEN=127.0.0.1:9200 serverload

Binding to a non-loopback address exposes an unauthenticated HTTP service. The recommended production configuration is the loopback default behind Apache.

ServerLoad refuses non-loopback listeners unless the exposure is explicitly acknowledged:

serverload --listen 0.0.0.0:9180 --allow-public-unauthenticated

Metrics are collected in a background task and cached in memory. The default refresh interval is three seconds; use a positive whole number of seconds to override it:

serverload --sample-interval 10

--sample-interval is a command-line option only. SERVERLOAD_LISTEN remains subject to the same non-loopback safety check as --listen.

History is retained in server memory for 24 hours by default. Use a positive whole number of hours to change it:

serverload --history-hours 48

--history-hours is a command-line option only. History starts empty after every server restart.

Install with systemd

sudo install -m 0755 target/release/serverload /usr/local/bin/serverload
sudo install -m 0644 deploy/systemd/serverload.service /etc/systemd/system/serverload.service
sudo systemctl daemon-reload
sudo systemctl enable --now serverload
curl http://127.0.0.1:9180/healthz

The supplied unit uses systemd's DynamicUser support, so no account creation is needed.

Apache

Enable the proxy modules and install one of the examples from deploy/apache:

sudo a2enmod proxy proxy_http headers
sudo install -m 0644 deploy/apache/serverload-http.conf /etc/apache2/sites-available/serverload.conf
sudo a2ensite serverload
sudo apachectl configtest
sudo systemctl reload apache2

Replace serverload.example.com before enabling a configuration.

Optional HTTPS

Use serverload-https.conf, replace its certificate paths, and enable ssl:

The Rust backend remains plain HTTP on loopback; Apache terminates TLS. Certificate provisioning and renewal remain the responsibility of the existing Apache/certificate tooling.

Optional Basic authentication

Use serverload-https-basic-auth.conf and create its password file outside any document root:

sudo htpasswd -c /etc/apache2/serverload.htpasswd your-user

Basic authentication must only be used over HTTPS. The example protects the dashboard, API, and externally proxied health endpoint together.

Development

cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test

The browser synchronizes every five seconds and keeps only a temporary rendering copy. Reloaded and resumed tabs recover retained history from the server and then fetch incremental updates using an opaque cursor.

License

MIT. The dashboard bundles Chart.js, which is also licensed under MIT; see THIRD_PARTY_NOTICES.md.