A tiny, self-hosted network speed test: a Rust standard-library backend, an embedded modern web UI, and an optional iperf3-compatible TCP server. There are no crate, JavaScript, font, image, or CDN dependencies.
The ready-to-run image is published at ghcr.io/eriksremess/speedtest:latest. The latest tag tracks the repository's default branch.
On Linux, host networking is recommended so container port forwarding does not affect the measurement.
With Podman:
podman run --rm --network host ghcr.io/eriksremess/speedtest:latestWith Docker:
docker run --rm --network host ghcr.io/eriksremess/speedtest:latestOpen http://localhost:8080. From another machine, use the server's LAN address.
By default, speedtest binds to ::. With host networking, this can make both ports reachable from other machines. Use --bind 127.0.0.1 for local-only access.
If host networking is unavailable, publish both ports instead. Replace docker with podman if preferred:
docker run --rm -p 8080:8080 -p 5201:5201 \
ghcr.io/eriksremess/speedtest:latest --bind 0.0.0.0Save this as compose.yaml on a Linux host:
services:
speedtest:
image: ghcr.io/eriksremess/speedtest:latest
network_mode: hostStart the service with:
docker compose up -dStop it with:
docker compose downWith a Rust toolchain and a checkout of this repository:
cargo run --releaseThe same default ports and bind address described above apply.
The iperf3-compatible server supports common TCP client commands:
iperf3 -c SERVER_ADDRESS
iperf3 -c SERVER_ADDRESS -R
iperf3 -c SERVER_ADDRESS -P 4It supports forward, reverse (-R), and parallel (-P) tests. UDP, SCTP, bidirectional mode, authentication, and advanced socket-tuning options are not supported. One iperf3 test runs at a time; the browser test remains available concurrently.
--bind ADDRESS Listen address (default: ::)
--http-port PORT Web/API port (default: 8080)
--iperf-port PORT iperf3 port (default: 5201)
--no-iperf Disable the iperf3 server
Pass options directly to the binary or after the container image name. When using Cargo, put them after --:
cargo run --release -- --no-iperfWith Docker, the equivalent container command is:
docker run --rm --network host \
ghcr.io/eriksremess/speedtest:latest --no-iperfThe same arguments work after the image name with Podman. In compose.yaml, use command: ["--no-iperf"] under the service.
The browser test measures median request latency, average variation between consecutive latency samples (jitter), and streamed download and upload throughput. These are application-path measurements, so browser memory, HTTP framing, and runtime overhead are part of the result. Use iperf3 for lower-level network benchmarking.
The minimal image runs as a non-root user. Build it locally with either engine:
podman build -t speedtest -f Containerfile .
docker build -t speedtest -f Containerfile .Run the local image with the same options shown in the quick start. Replace podman with docker if preferred:
podman run --rm --network host speedtestFor streamed uploads through nginx, disable proxy buffering and allow the full timed request body:
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
client_max_body_size 2g;
proxy_request_buffering off;
proxy_buffering off;
}The HTTP health endpoint is available at /health and returns {"status":"ok"}.