Nettest is a high-performance server and client for network speed measurement, written in Rust. The tool supports modern communication protocols and provides real-time accurate measurements with beautiful visualization.
π Complete Documentation: https://specure.github.io/nettest/docs
- Multithreading - Handle multiple clients simultaneously
- Asynchronous architecture - Efficient resource utilization
- Connection queue - Smart load distribution between workers
- TCP connections - Direct connection for maximum performance
- WebSocket - Browser client support
- TLS/SSL - Secure connections
- Interactive speed graphs - Real-time download and upload visualization
- Beautiful UI - Modern, responsive interface
- Live measurements - See your network performance in real-time
- Configurable number of workers
- Configurable ports and addresses
- SSL/TLS certificate support
Experience real-time network measurements with beautiful visualization
π Launch Measurement InterfaceDownload the latest builds from the GitHub Releases page.
Note:
- Download the appropriate archive for your architecture and distribution
- Extract:
- Linux/macOS:
tar -xzf nettest-<distribution>-<arch>.tar.gz- Windows: Extract the ZIP file
- Run:
- Linux/macOS:
./nettest -s(server) or./nettest -c <address>(client)- Windows:
nettest.exe -s(server) ornettest.exe -c <address>(client)
# Debug build
cargo build
# Release build with optimizations
cargo build --releaseThe project includes automated builds via GitHub Actions:
- Ubuntu builds: Latest and LTS versions with native compilation
- Debian builds: Multiple versions (11, 12) for maximum compatibility
- macOS builds: Apple Silicon and Intel architectures
- Windows builds: x86_64 and ARM64 architectures
# Basic run
nettest -snettest -s also serves a browser speed test on the measurement port. On start it prints the
addresses to open (and a QR code for phones):
Nettest is running. Open the speed test on any device on this network:
http://192.168.1.10:5005/
http://nettest.local:5005/
Opening the page connects to the server it was loaded from and starts measuring right away (ping, download, upload). No certificates, no configuration and nothing to install on the device with the browser. The client is the same Rust measurement code as the CLI, compiled to WebAssembly (the whole page is ~160 KB gzipped, embedded in the binary).
Notes:
- Plain HTTP is enough for ping, download and upload. Packet loss needs WebTransport, which
browsers only allow on HTTPS (or
localhost) pages; over plain HTTP jitter is derived from the ping round trips and the page leaves packet loss out. ?autostart=0opens the page without starting a measurement. All client options are in the settings panel and can be passed as URL parameters ("Copy link with settings").- Turn the page or the mDNS announcement off in
nettest.conf:enable_web_ui = false,enable_mdns = false.
With enable_upstream_test = true, the page measures three legs, one after the other:
- this device β the nettest server (the normal browser test),
- the server β the internet: the server runs the nettest client itself against the nearest
public measurement server (or
upstream_server), - this device β the internet: the browser measures the same public server directly.
It then says whether the Wi-Fi/LAN, the internet line or the server itself is the bottleneck,
with a This device / Server / Internet diagram, three concentric result rings on one scale and a
comparison table. The breakdown only runs for devices on the server's own network; visitors
from the internet get the plain test. Speeds don't add up: end to end should be close to the
slower leg; ping does add up. The
server also notes whether other devices used the line during its test and whether its CPU
was saturated. The /api/upstream/* endpoints only answer devices on the local network,
require an X-Nettest: 1 header, reject cross-origin requests and allow one run per minute.
When the browser runs on the server itself, the local segment is only loopback and the server's internet is this device's internet, so the page runs a single test: this device against the nearest public measurement server.
nettest -s -demo (presentation mode) turns the upstream test on even without
enable_upstream_test, always runs all three segments whatever the path, and drops the
one-run-per-minute limit.
Rebuilding the browser client after changes to web/ or src/wasm/:
rustup target add wasm32-unknown-unknown
cargo install wasm-bindgen-cli --version <wasm-bindgen version from Cargo.lock>
./scripts/build-web.sh # writes gzipped files to dist/ and dist.sha256 (wasm-opt optional)
cargo build --release # embeds dist/Commit dist/ together with dist.sha256. CI runs ./scripts/build-web.sh --check and fails
when web/ or the WASM client changed without a rebuild.
# TCP client
nettest -c <SERVER_ADDRESS>
# WebSocket client
nettest -c <SERVER_ADDRESS> -ws
# TLS client
nettest -c <SERVER_ADDRESS> -tls
# Machine-readable output
nettest -c <SERVER_ADDRESS> -jsonBy default the client prints a table meant for humans. Two flags switch to machine-readable output, which keeps stdout free of anything but the result:
| Flag | Output |
|---|---|
-raw |
One line: ping/download/upload, latency in ms and speed in Gbit/s |
-json |
A JSON document with every measured value |
The JSON document reports nettest's native units: milliseconds for latency and
jitter, bits per second for speed, percent for packet loss and bytes for the
transferred volume. A value that was not measured is left out instead of being
reported as zero, so a consumer can tell "not measured" apart from "measured as
zero". With -legacy, for example, jitter_ms and packet_loss_percent are
absent because no VoIP and no UDP test ran.
$ nettest -c 192.168.1.100 -json
{
"type": "measurement",
"timestamp": "2026-08-05T12:34:56Z",
"client": {
"name": "nettest",
"version": "2.1.0"
},
"server": {
"host": "192.168.1.100",
"port": 5005
},
"protocol": "tcp",
"num_threads": 3,
"failed_threads": 0,
"ping": {
"latency_ms": 12.34,
"jitter_ms": 0.42
},
"download": {
"speed_bps": 942123456,
"bytes_transferred": 1177654320
},
"upload": {
"speed_bps": 512345678,
"bytes_transferred": 640432098
},
"packet_loss_percent": 0.0
}jitter_ms is the mean jitter measured by the VoIP test on an idle line. It is
not the jitter under download or upload load, because nettest does not measure
that.
Progress messages, warnings and errors go to stderr in every mode, so piping stdout into a parser needs no filtering:
nettest -c 192.168.1.100 -json | jq .download.speed_bps| Parameter | Description | Default |
|---|---|---|
-l |
TCP listen address and port | 5005 |
-L |
TLS listen address and port | 443 |
-c |
Path to SSL certificate (PEM format) | - |
-k |
Path to SSL key file (PEM format) | - |
-udp |
UDP port for VoIP/packet loss tests | 5004 |
-u |
Drop privileges to specified user | - |
-d |
Run as daemon in background | false |
-t |
Number of worker threads | - |
-log |
Log level (info, debug, trace) | - |
| Parameter | Description | Default |
|---|---|---|
-c |
Server address | auto-discover |
-tls |
Use TLS connection | false |
-ws |
Use WebSocket connection | false |
-t |
Number of threads | 3 |
-p |
TCP/TLS port | 5005 |
-g |
Generate graphs | false |
-raw |
Print one parseable line: ping/download/upload |
false |
-json |
Print the measurement as JSON on stdout | false |
-legacy |
Use legacy PUT command (skip VoIP/packet loss) | false |
-log |
Log level (info, debug, trace) | - |
Direct TCP connection for maximum performance:
Client <ββTCPββ> Server
Browser client support:
Client <ββWebSocketββ> Server
Secure connections:
Client <ββTLSββ> Server
Nettest is optimized for high performance:
- Multithreading: One server can support multiple clients
- Asynchronous processing: Efficient CPU and memory usage
- Smart queue: Automatic load distribution between workers
- Minimal latency: Optimized architecture for accurate measurements
- Live speed change visualization
- Detailed upload and download statistics
- Interactive charts with smooth animations
- Download speed - Real-time download performance
- Upload speed - Real-time upload performance
- Ping - Network round-trip time (median)
- Jitter - VoIP quality metric (RFC 3550), requires server v2.0+
- Packet Loss - UDP packet loss rate (RFC 6673), requires server v2.0+
Note: Jitter and Packet Loss tests use UDP port
5004by default.
Open this port on the server firewall:iptables -A INPUT -p udp --dport 5004 -j ACCEPT
- Rust: 1.70+ (latest stable)
- Linux/macOS/Windows: Support for all major platforms
- Source code: Apache License 2.0 (LICENSE.txt)
Nettest - Your reliable tool for network speed measurement! π

