Replace speed test with LibreSpeed engine: fix 4x-slow upload

Single 512 MB POST over HTTP/2 was throttled by the per-stream h2
flow-control window, reading ~4x low. LibreSpeed uses parallel upload
streams measured via XHR progress events, which amortizes the window
limit (h2 must stay on for trojan-gRPC).

- Vendor speedtest.js + speedtest_worker.js (LGPL) into assets
- mtr-backend.py: ThreadingHTTPServer, /api/st/up upload sink,
  /api/st/getip; parallel streams need concurrent handling
- nginx: speedtest locations without limit_req (limit_conn instead),
  ping answered by nginx directly, h2 preread/body buffer tuning
- No telemetry, no database
- Drop 512 MB test file; patch script now also substitutes
  __SERVER_DOMAIN__/__SERVER_IP__ placeholders

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Ivan Razin
2026-07-03 14:15:22 +03:00
co-authored by Claude Fable 5
parent cb9aa79470
commit de1d95e6e0
6 changed files with 1295 additions and 95 deletions
+37 -10
View File
@@ -438,6 +438,9 @@ server {
root /var/www/html/;
real_ip_header proxy_protocol;
set_real_ip_from 127.0.0.1;
# Larger h2 preread window improves single-stream upload throughput
http2_body_preread_size 128k;
client_body_buffer_size 512k;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!eNULL:!MD5:!DES:!RC4:!ADH:!SSLv3:!EXP:!PSK:!DSS;
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem;
@@ -498,21 +501,39 @@ server {
proxy_send_timeout 120s;
}
# ── Speed test upload receiver ───────────────────────────────────────────
# proxy_request_buffering off = nginx streams body to backend in real time;
# backend responds only after reading all bytes → accurate timing on client
location ^~ ${diag_path}api/upload {
limit_req zone=diag_page burst=5 nodelay;
proxy_pass http://127.0.0.1:${mtr_backend_port}/api/upload;
# ── LibreSpeed upload sink ───────────────────────────────────────────────
# No limit_req: librespeed fires many short POSTs (parallel streams).
# proxy_request_buffering off = client sees true network backpressure.
location ^~ ${diag_path}api/st/up {
access_log off;
limit_conn per_ip 8;
proxy_pass http://127.0.0.1:${mtr_backend_port}/api/st/up;
proxy_http_version 1.1;
proxy_set_header X-Real-IP \$remote_addr;
proxy_request_buffering off;
client_max_body_size 600m;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
client_max_body_size 64m;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
add_header Cache-Control "no-store" always;
}
# ── LibreSpeed ping endpoint (answered by nginx, no backend hop) ─────────
location = ${diag_path}api/st/ping {
access_log off;
limit_conn per_ip 8;
add_header Cache-Control "no-store" always;
default_type text/plain;
return 200 "";
}
# ── LibreSpeed client IP ─────────────────────────────────────────────────
location = ${diag_path}api/st/getip {
proxy_pass http://127.0.0.1:${mtr_backend_port}/api/st/getip;
proxy_http_version 1.1;
proxy_set_header X-Real-IP \$remote_addr;
add_header Cache-Control "no-store" always;
}
# ── Download test files ──────────────────────────────────────────────────
location ^~ ${diag_path}testfiles/ {
alias /var/www/diagnostics/testfiles/;
@@ -940,14 +961,20 @@ install_diagnostics() {
-e "s|__SERVER_IP__|${IP4}|g" \
"${diag_webroot}/index.html"
# LibreSpeed engine (speed test frontend, LGPL — github.com/librespeed/speedtest)
curl -fsSL "${GITHUB_RAW}/assets/diagnostics/librespeed/speedtest.js" \
-o "${diag_webroot}/speedtest.js"
curl -fsSL "${GITHUB_RAW}/assets/diagnostics/librespeed/speedtest_worker.js" \
-o "${diag_webroot}/speedtest_worker.js"
# Test download files
local testfiles="${diag_webroot}/testfiles"
mkdir -p "${testfiles}"
[[ -f "${testfiles}/test-15k.bin" ]] || dd if=/dev/zero bs=1024 count=15 of="${testfiles}/test-15k.bin" status=none
[[ -f "${testfiles}/test-17k.bin" ]] || dd if=/dev/zero bs=1024 count=17 of="${testfiles}/test-17k.bin" status=none
[[ -f "${testfiles}/test-100m.bin" ]] || dd if=/dev/zero bs=1048576 count=100 of="${testfiles}/test-100m.bin" status=none
[[ -f "${testfiles}/test-512m.bin" ]] || dd if=/dev/zero bs=1048576 count=512 of="${testfiles}/test-512m.bin" status=none
[[ -f "${testfiles}/test-1g.bin" ]] || dd if=/dev/zero bs=1048576 count=1024 of="${testfiles}/test-1g.bin" status=none
rm -f "${testfiles}/test-512m.bin" # only used by the old single-stream speed test
chown -R www-data:www-data "${diag_webroot}" 2>/dev/null || true
# MTR backend Python script