- For a quick download figure, curl needs no installation:
curl -o /dev/null -w '%{speed_download}\n' <url>prints bytes per second. - Multiply bytes per second by 8 and divide by 1,000,000 to get megabits per second, the unit your provider quotes.
- speedtest-cli gives you the familiar Ookla download, upload and ping figures on a headless box.
- iperf3 is the only one of the three that measures the link between two machines you control, without a third-party server in the path.
- A slow result is often latency or a slow test endpoint, not bandwidth. Always test more than one destination before you raise a ticket.
How do I run a speed test from the Linux terminal?
The fastest way is curl, which is already installed on nearly every Linux server. Point it at a large test file, discard the output, and ask it to print the transfer rate. No package to install, no dependencies, and it works over SSH on a server with no desktop.
curl -o /dev/null -w 'Speed: %{speed_download} bytes/sec\n' \
'https://speed.cloudflare.com/__down?bytes=100000000'That prints bytes per second. Internet connections are sold in megabits per second, so pipe it through awk to get the unit you actually want to compare against your contract.
curl -s -o /dev/null -w '%{speed_download}\n' \
'https://speed.cloudflare.com/__down?bytes=100000000' \
| awk '{printf "%.2f Mbit/s\n", $1 * 8 / 1000000}'Quote the URL
The test URL contains a question mark and often an ampersand. Without single quotes your shell will try to interpret them and either run the command in the background or fail outright.
How do I test upload speed with curl?
Upload is the half people forget, and it is the half that matters when you are pushing backups offsite or serving a busy site. Create a file of known size, POST it, and read the speed_upload counter. Delete the file afterwards.
# 1. Create a 50 MB file of zeroes
dd if=/dev/zero of=/tmp/uptest bs=1M count=50
# 2. Upload it and print the rate
curl -s -o /dev/null -w '%{speed_upload}\n' \
-X POST --data-binary @/tmp/uptest \
https://speed.cloudflare.com/__up \
| awk '{printf "Upload: %.2f Mbit/s\n", $1 * 8 / 1000000}'
# 3. Clean up
rm /tmp/uptestCheck you have the disk space first
On a small VPS with a nearly full disk, dd will happily fill the last free gigabyte and take the site down with it. Run df -h /tmp before you create the file. See how to check CPU, memory and disk usage if you are not sure how much headroom you have.
What do the curl timing variables tell me?
This is where curl beats a browser speed test. The same -w flag exposes every stage of the request separately, so you can see whether a slow page is DNS, the TCP handshake, TLS negotiation, or the server thinking. That last one is Time to First Byte, and it is usually the number that matters.
curl -s -o /dev/null -w '\
DNS lookup: %{time_namelookup}s\n\
TCP connect: %{time_connect}s\n\
TLS handshake: %{time_appconnect}s\n\
First byte: %{time_starttransfer}s\n\
Total: %{time_total}s\n\
Download speed: %{speed_download} bytes/sec\n' \
https://example.com/| Variable | What it measures | What a bad number means |
|---|---|---|
| time_namelookup | Resolving the hostname to an IP | Slow or distant DNS resolver, or no local cache |
| time_connect | TCP handshake to the server | Network distance or a congested link |
| time_appconnect | TLS negotiation | Slow certificate chain or an old TLS version |
| time_starttransfer | Time to first byte: the server thinking | The application or database is slow, not the network |
| time_total | The whole request | Compare against first byte to see if the body is the problem |
Reading the stages separately turns "the site feels slow" into a specific thing to fix.
If time_starttransfer is over a second but time_connect is fast, no amount of bandwidth will help you: the server is slow, not the pipe. That is a hosting or application problem, and our WordPress performance guide covers the server side of it.
How do I install and use speedtest-cli?
speedtest-cli gives you the familiar Ookla numbers (download, upload and ping) against a nearby test server, chosen automatically. It is a Python tool, so it needs installing, but it is the closest terminal equivalent to what people mean by a speed test.
# Debian / Ubuntu
sudo apt update && sudo apt install -y speedtest-cli
# AlmaLinux / Rocky / CentOS Stream (needs EPEL)
sudo dnf install -y epel-release
sudo dnf install -y speedtest-cli
# Any distribution with pip
pip3 install --user speedtest-cli# Full test
speedtest-cli
# Just the numbers, no progress output
speedtest-cli --simple
# Report in bytes rather than bits
speedtest-cli --bytes
# Pick a specific test server
speedtest-cli --list | head -20
speedtest-cli --server 12345--simple is the one to use in scripts and cron jobs: three lines of output, nothing to parse around.The automatic server choice is not always the best one
speedtest-cli picks the server with the lowest ping, which is often a small regional host that cannot saturate a gigabit port. If your result looks low, run speedtest-cli --list, pick a large well-connected provider, and test again with --server.
When should I use iperf3 instead?
curl and speedtest-cli both measure the path to somebody else's server. iperf3 measures the path between two machines you control, which is what you want when you are testing a link between two of your own servers, or proving to a provider that a specific route is slow.
# Install on both machines
sudo apt install -y iperf3 # Debian / Ubuntu
sudo dnf install -y iperf3 # AlmaLinux / Rocky
# On the receiving machine, start a listener
iperf3 -s
# On the sending machine
iperf3 -c 203.0.113.10
# Test the reverse direction (server sends to client)
iperf3 -c 203.0.113.10 -R
# Four parallel streams, which is closer to how real traffic behaves
iperf3 -c 203.0.113.10 -P 4| Tool | Measures | Needs installing | Best for |
|---|---|---|---|
| curl | Download, upload and per-stage timings | No | A quick check, and diagnosing where the time goes |
| speedtest-cli | Download, upload, ping to a public server | Yes | A number you can compare with a home broadband test |
| iperf3 | Throughput between two machines you own | Yes, on both ends | Proving a specific route or link is underperforming |
Pick by what you are trying to prove, not by which one is quickest to type.
Why is my server speed test slower than I expected?
Most disappointing results are not a bandwidth problem. Before you open a ticket, rule out the four causes below, in this order. They account for the large majority of cases we see.
- 1A single TCP stream cannot fill a fast link over distance. One connection to a server 5,000 miles away will plateau well below your port speed no matter how good the network is. Re-test with
iperf3 -P 4or against a closer endpoint before concluding anything. - 2The test endpoint is the bottleneck. Public test files are shared with everybody else testing at that moment. Run the same command against two or three different destinations. If one is slow and the others are fine, the endpoint was the problem.
- 3The server is busy. A box that is already saturating its CPU on PHP or its disk on a database query has nothing left to drive the network with. Check load first with top, htop and the standard resource commands.
- 4Something else is using the link. A backup, a large rsync or a busy site will happily eat the bandwidth you are trying to measure. nload shows you live inbound and outbound throughput so you can see what the baseline was before your test started.
Test more than once, at more than one time of day
A single result is an anecdote. Run the test three times over a few hours and record the numbers. A link that is fast at 6am and slow at 8pm is a contention problem, which is a completely different conversation with a provider than a link that is slow all the time.
If the bandwidth is fine but pages are still slow, the network was never the issue. Server response time is what visitors actually feel, and it is decided by CPU, database and caching rather than throughput. Core Web Vitals for WordPress explains which measurement matters for which symptom.
How do I log speed test results over time?
One measurement tells you almost nothing. A week of measurements tells you whether the problem is constant, time-of-day contention, or a one-off. A three-line cron job is enough.
# Log download speed in Mbit/s every hour, with a timestamp
0 * * * * root curl -s -o /dev/null -w '%{speed_download}\n' \
'https://speed.cloudflare.com/__down?bytes=25000000' \
| awk -v d="$(date -Is)" '{printf "%s %.2f\n", d, $1*8/1000000}' \
>> /var/log/speedtest.logAdd the log to logrotate so it cannot grow without limit. Understanding Linux system logs covers rotation and where everything lives.
Frequently asked questions
Can curl really measure internet speed accurately?
Yes, for download and upload throughput, provided the file is large enough (50 MB or more) and the test endpoint is not itself the bottleneck. What curl cannot do is pick a good nearby server for you, which is what speedtest-cli adds. For a single-number answer use speedtest-cli; for diagnosing where the time goes, curl's timing variables are better.
Why does curl report speed in bytes per second and not megabits?
curl reports bytes because that is what it transferred. Providers quote megabits. To convert, multiply bytes per second by 8 and divide by 1,000,000. So 12,500,000 bytes/sec is 100 Mbit/s. Piping the output through awk, as shown above, does the sum for you.
How do I run a speed test on a server with no internet-facing access?
Use iperf3 between the server and another machine on the same network or over your private link. It needs no external endpoint, so it works on isolated hosts. Start iperf3 -s on one machine and iperf3 -c <ip> on the other.
Does a speed test tell me if my website is slow?
Rarely. Bandwidth almost never limits a normal website: a page is a few hundred kilobytes and the connection moves that in milliseconds. What visitors feel is Time to First Byte, which is CPU, database and caching. Use curl's time_starttransfer figure for that, not speed_download.
Is speedtest-cli still maintained?
The original Python speedtest-cli is still packaged by every major distribution and still works. Ookla also publish their own official binary as speedtest, which supports more servers and reports more detail. Either is fine for a terminal test; the Python one is easier to install from your distribution's repositories.
About G7Cloud Engineering
Articles written by the engineers who build and run G7Cloud: UK managed hosting and the AI Website Builder. We write about what we operate every day: containers, backups, databases, and the small-business websites that run on them.
More about G7Cloud →