If this edition helps you, I'd appreciate a small donation – thank you! ☕
Bandbreiten- und Latenztest im eigenen Netz: Seite aufrufen, Start drücken, nach rund 25 Sekunden stehen Download, Upload, Latenz im Leerlauf, Latenz unter Download- und unter Upload-Last, Jitter und eine Bufferbloat-Note da – dazu ein Verlaufsdiagramm des ganzen Laufs.
Der Container ist Weboberfläche und Messgegenstelle in einem. Gerechnet wird im Browser des Clients, gemessen also die tatsächliche Strecke Handy/Laptop ↔ Docker-Host – nicht die Internetleitung.
Alles auf Deutsch, dunkler Stil, keine Anmeldung, keine Cloud, keine Datenbank, keine Fremdbibliothek – der Server ist reine Node-Standardbibliothek.
docker run -d --name speedtest \
-p 8088:8080 \
--restart unless-stopped \
andyxtreme/speedtest:latest
Danach vom Client im Netz: http://<docker-host>:8088
Mit Compose:
services:
speedtest:
image: andyxtreme/speedtest:latest
container_name: speedtest
ports:
- "8088:8080"
restart: unless-stopped
Der Host-Port links ist frei wählbar, 8080 im Container bleibt.
| Port | 8080 im Container |
| Volumes | keine – der Container schreibt nichts, hält nichts vor, merkt sich nichts |
| Healthcheck | ist im Image enthalten, prüft /healthz |
| Benutzer | läuft als node, nicht als root |
| Variable | Standard | Zweck |
|---|---|---|
PORT | 8080 | Port im Container |
HOST | 0.0.0.0 | Listen-Adresse |
MAX_DOWNLOAD_BYTES | 8589934592 | Obergrenze je Download-Anfrage (8 GiB) |
| Pfad | |
|---|---|
GET / | Weboberfläche |
GET /download?bytes=N | N Byte Zufallsdaten, nicht komprimierbar |
POST /upload | verwirft den Inhalt, meldet die empfangene Byte-Zahl zurück |
GET /ping | 204, HTTP-Fallback der Latenzmessung |
GET /ws | WebSocket-Echo für die Latenzmessung |
GET /api/info | Server- und Client-Adresse |
GET /healthz | Healthcheck |
| Wert | Wie er entsteht |
|---|---|
| Download | 6 parallele Verbindungen, 8 s Messfenster nach 2 s Anlauf |
| Upload | 3 parallele Verbindungen, gleiche Fensterlogik |
| Ruhe-Latenz | Median aus 22 Pings ohne Last |
| Jitter | mittlere absolute Abweichung aufeinanderfolgender Ruhe-Pings |
| Latenz unter Download-Last | Median der Pings während der Download-Phase |
| Latenz unter Upload-Last | Median der Pings während der Upload-Phase |
| Bufferbloat | Note A+ bis F für den größten Latenzanstieg gegenüber Ruhe |
Die beiden Latenzen unter Last sind der eigentliche Punkt: Eine Leitung, die im Leerlauf 8 ms hat und unter Last auf 300 ms geht, fühlt sich beim Videocall kaputt an – im reinen Bandbreitenwert sieht man davon nichts.
Browser erlauben nur sechs gleichzeitige HTTP/1.1-Verbindungen pro Origin. Liefen
die Pings über HTTP, würden sie sich hinter den Lastverbindungen einreihen, und
die gemessene Latenz unter Last wäre systematisch zu hoch – man würde die
Warteschlange des eigenen Browsers messen statt das Netz. Die Pings laufen
deshalb über einen WebSocket-Echo auf /ws.
Kommt der WebSocket nicht zustande, etwa weil ein Proxy das Upgrade schluckt, schaltet der Client selbsttätig auf HTTP-Pings um. Was gerade benutzt wird, steht in der Kopfzeile der Seite.
TCP braucht einige hundert Millisekunden bis zur vollen Fenstergröße, und beim Upload meldet der Browser zunächst Bytes, die nur im Socket-Puffer stehen. Die Anlaufphase fließt deshalb weder in den Durchsatz noch in die Latenz unter Last ein.
Ohne Anpassung misst man den Proxy statt der Leitung:
/ws muss durchgereicht werden, sonst fällt die
Latenzmessung auf HTTP zurück.proxy_buffering off,
proxy_request_buffering off), sonst puffert der Proxy den Upload und die
Messung zeigt seine Geschwindigkeit.client_max_body_size 0), sonst bricht der
Upload nach wenigen Megabyte ab.Im LAN ist der direkte Weg ohne Proxy und ohne TLS der ehrlichere.
Kein Internet-Speedtest. Gemessen wird bis zum Docker-Host, nicht bis zum Provider. Für einen WAN-Test müsste der Container an der Gegenstelle laufen.
Bei sehr schnellen Verbindungen ist irgendwann nicht mehr das Netz die Grenze, sondern die CPU des Clients – auf einem älteren Handy im WLAN merkt man das zuerst. Und wer über WLAN misst, misst in aller Regel das WLAN.
Browserseitig werden Fetch-Streams gebraucht: aktuelle Chrome-, Edge- und Firefox-Versionen, Safari und iOS seit 2021.
| Tag | |
|---|---|
latest | jeweils aktueller Stand |
1.0 | feste Version |
Gebaut für linux/amd64.
Quelltext und ausführliche Dokumentation liegen als README.md im
Projektverzeichnis.
Content type
Image
Digest
sha256:b74e6cce9…
Size
55.1 MB
Last updated
18 days ago
docker pull andyxtreme/speedtest