Self-hosted speed test server (backend + frontend), Docker-based, on a fresh RamNode KVM instance.
Assumptions
- RamNode KVM VPS, Ubuntu 24.04 LTS
- Public IPv4 (and optionally IPv6) already assigned
- You have root or sudo access via SSH
1. Base provisioning
apt update && apt -y upgrade
apt -y install ca-certificates curl gnupg ufwSet hostname (optional, useful if this node is dedicated to speedtest):
hostnamectl set-hostname speedtest.example.com2. Install Docker
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin
systemctl enable --now docker3. Deploy LibreSpeed container
Using the maintained community image (adolfintel/speedtest or linuxserver/librespeed). LinuxServer's image is easiest to configure:
mkdir -p /opt/librespeed/config
cat > /opt/librespeed/docker-compose.yml <<'EOF'
services:
librespeed:
image: lscr.io/linuxserver/librespeed:latest
container_name: librespeed
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
- PASSWORD= # optional: set to password-protect results/stats page
- CUSTOM_RESULTS=false
volumes:
- /opt/librespeed/config:/config
ports:
- "80:80"
- "443:443"
restart: unless-stopped
EOF
cd /opt/librespeed
docker compose up -dVerify:
docker ps
curl -I http://localhost/4. Firewall
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable5. TLS (recommended — speed test results page and some browsers expect HTTPS)
Put Caddy or nginx + certbot in front, or swap ports in the compose file and let LinuxServer's built-in nginx handle it if you supply certs. Quickest path with Caddy as reverse proxy:
apt -y install debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt update && apt -y install caddyChange LibreSpeed compose to bind 127.0.0.1:8080:80 instead of 80:80, then:
cat > /etc/caddy/Caddyfile <<'EOF'
speedtest.example.com {
reverse_proxy 127.0.0.1:8080
}
EOF
systemctl reload caddyCaddy auto-provisions Let's Encrypt certs on first request — no certbot needed.
6. Bandwidth / abuse considerations specific to a VPS
- LibreSpeed's default test file sizes (up to 100MB chunks) can saturate a small VPS's port speed and burn through metered bandwidth fast if this is public. Check the plan's bandwidth cap before opening it to the internet unauthenticated.
- Consider
iptables/ufwrate limiting or fronting with a reverse proxy that caps concurrent connections if abuse is a concern. - If this is for internal RamNode network diagnostics only, bind to a private/internal IP instead of
0.0.0.0and skip the public firewall rules for 80/443.
7. Validate
Open https://speedtest.example.com in a browser — you should get the standard LibreSpeed UI and a working download/upload/ping/jitter test against this VPS.
Notes / variations
- Native (non-Docker) install is also viable via PHP-FPM + nginx if Docker isn't wanted on this box — LibreSpeed backend is just PHP + a JS frontend, no database required.
- For multi-region testing, deploy this same stack on VPS instances in each RamNode datacenter and link them from a single results/frontend host.
