SSD Nodes Learn 🎉 VPS from $5.50/mo
Guides Matt ConnorBy Matt Connor

How to read a cheap VPS offer

A line by line teardown of a cheap VPS listing: vCPU oversell, unlimited bandwidth clauses, NVMe claims, renewal pricing, and a 30 minute acceptance test.

What a cheap VPS offer leaves out

Read a cheap VPS offer backwards, because the price is the least useful number on the page. What decides whether the box is any good is the part the listing does not print: the oversell ratio behind the vCPU count, the fair use clause behind the word "unlimited", the renewal price after the first term, and whether backups and the IPv4 address are billed on top. This guide walks a listing line by line, then gives you an acceptance test to run on the box while you can still ask for your money back.

None of this says a low price is a trick. Older hardware, denser packing, self-service support and thinner platform redundancy are how a low price is possible at all. The job is to know which trade you accepted before your users find it for you. Everything below runs on Ubuntu 24.04 with the packages available in August 2026.

A vCPU is not a core

A vCPU is a scheduling slot rather than a piece of silicon. On KVM (kernel-based virtual machine) each vCPU is a thread on the host, and the host scheduler puts that thread on a physical core when its turn comes. A host can sell four vCPUs against one physical core, and every guest still reports its full count in nproc. The number in the listing is a ceiling on what you may ask for, and it says nothing about what is held for you.

The oversell ratio is how many vCPUs a host sells per physical core. At 1:1 the core is yours alone. Cheap plans run higher, and the ratio is almost never published, so read any listing that does not say "dedicated core" or "dedicated vCPU" as shared. Shared works for most jobs, because most servers are idle most of the time. It stops working when your busy hour is also everybody else's busy hour.

You can measure the effect from inside the guest. When your vCPU is ready to run and the host gives the physical core to another guest, that wait is counted as steal time: the st column in vmstat and %st in top. Steal time is how a noisy neighbour shows up in your own metrics, and it is the most useful number in this guide, because a listing cannot fake it.

A dedicated core is still shared in other ways. Memory bandwidth, the last level cache and the storage path belong to the whole host. "Dedicated vCPU" removes the largest source of variance. It does not remove all of it.

Check the CPU model too, with lscpu. Two plans can both say "4 vCPU" while their single thread speed differs by a factor of two, because one host is several CPU generations older. Old silicon at a low price is a fair trade for a build agent and a poor one for a checkout page.

"Unlimited bandwidth" is at least four different products

Traffic gets described in four ways, and they are not interchangeable.

  • A metered allowance. The listing gives a number, "2 TB per month" or similar. What matters is what happens after it: an overage charge per extra TB, or a speed cut to something very slow until the month rolls over. Find out which one before you need to know.
  • An unmetered plan with a fair use clause. Traffic is not counted, and the acceptable use policy sets the limit in words instead of numbers. Search that document for "fair use", "sustained", "excessive" and "abuse".
  • A port speed cap. A 100 Mbit/s port limits you by physics, whatever the traffic policy says.
  • A blend of the last two: unmetered traffic on a slow port. This is the most common shape on cheap plans, and it is an honest offer as long as you read the port speed.
ChartTraffic ceiling set by port speed alone, 30 days at full rate
The data behind this chart
[
  {
    "label": "100 Mbit/s",
    "tb_ceiling_30d": 32,
    "hours_per_tb": 22.2
  },
  {
    "label": "200 Mbit/s",
    "tb_ceiling_30d": 65,
    "hours_per_tb": 11.1
  },
  {
    "label": "500 Mbit/s",
    "tb_ceiling_30d": 162,
    "hours_per_tb": 4.4
  },
  {
    "label": "1 Gbit/s",
    "tb_ceiling_30d": 324,
    "hours_per_tb": 2.2
  }
]

A port speed is a hard ceiling, and the arithmetic is simple. 100 Mbit/s is 12.5 megabytes per second, so 30 days of that port at full rate moves about 32 TB. The same 30 days on a 1 Gbit/s port give 324 TB. TB here means 10^12 bytes, the unit hosts bill in. This is arithmetic, not a measurement, and no real server runs its port flat out for a month.

The second column is the one that changes plans. Moving a single terabyte takes about 22.2 hours on the 100 Mbit/s port and 2.2 hours on the gigabit port. If your recovery plan is "pull the backup down and start again", that number is your recovery time.

Two more details hide in this line of the spec. "1 Gbit/s shared" means the port is shared with other guests, so the ceiling above is a best case rather than a promise. And some hosts bill traffic at the 95th percentile of the sampled rate instead of by total volume, which prices a steady load far below a spiky one.

Whatever the plan says, measure your own use. vnstat reads the interface counters and keeps history.

sudo apt install -y vnstat
sudo systemctl enable --now vnstat
vnstat -d
vnstat -m

Right after install, vnstat prints Not enough data available yet. because its database has no samples. Come back the next day, and vnstat -m gives you a monthly total to compare against the allowance you are paying for.

Is the NVMe claim real, and can you check it?

lsblk -d -o NAME,ROTA,SIZE,MODEL

ROTA of 0 means the guest was told the device is not rotational. That value comes from the hypervisor, so it describes what the host advertises rather than the media underneath. The MODEL column is usually empty for a virtio disk such as /dev/vda, and shows a generic QEMU HARDDISK for a SCSI attached one. You are looking at a virtual disk, so its label proves nothing.

The property worth checking is latency, and the real split is between local NVMe and a network attached volume. A network volume can post a large sequential throughput figure and still feel slow, because throughput is measured with many requests in flight while a database waits for one small write at a time. Measure at queue depth 1 for latency, then at a deeper queue for IOPS (input/output operations per second).

sudo apt install -y fio
fio --name=lat --filename=fiotest --size=1G --direct=1 --ioengine=libaio --rw=randread --bs=4k --iodepth=1 --numjobs=1 --runtime=60 --time_based --group_reporting
fio --name=iops --filename=fiotest --size=1G --direct=1 --ioengine=libaio --rw=randread --bs=4k --iodepth=32 --numjobs=1 --runtime=60 --time_based --group_reporting
rm -f fiotest

Read the clat percentiles block, and specifically the 99.00th line. That is the completion latency your slowest one percent of requests saw, and it is what a user feels as a stall. As a rough guide, local NVMe at queue depth 1 answers in the hundreds of microseconds, and a network attached volume answers in milliseconds. Compare your own two runs instead of trusting any single published figure, and run the pair three times across a day, because a disk shared with other tenants behaves differently at 03:00 and at 20:00.

fio lays the 1 GB file down first, so leave room on the disk, and remember the test spends any IOPS allowance the plan applies. When you only want a quick reading, ioping -c 20 . gives you latency in one line. A benchmark is only worth anything if you can repeat it, so save the exact command lines and the output with the date attached.

What is included, and what is billed on top

  • IPv4. One address is normally included. Some cheap plans hand you a shared address behind NAT (network address translation) with a few forwarded ports, which means you cannot run anything on port 443 of your own. Check with ip -4 addr show scope global and curl -4 https://icanhazip.com. Two different answers mean you are behind NAT.
  • IPv6. A routed /64 gives you addresses for containers and for anything you want reachable from outside. A single /128 covers outbound traffic and little else.
  • Backups. Automatic backups are usually a paid add-on. Snapshots are often free, but a snapshot lives on the same infrastructure as the disk it copies, so it protects you from your own mistakes and not from losing the host. Keep one copy off the box whatever the plan includes.
  • DDoS handling. Many hosts answer a volumetric attack (distributed denial of service) by null routing your IP address for a fixed period. The server stays healthy. It is simply unreachable from the internet. Ask for the trigger threshold and for how long the null route lasts.
  • Support scope. On an unmanaged plan you are the system administrator, and the host's responsibility ends at the hypervisor and the network. That is the largest real cost difference between two plans with identical specifications.
  • Licences and panels. A control panel, a commercial operating system or a mail add-on can cost more each month than the server does.

Which virtualization type are you buying?

systemd-detect-virt

kvm or qemu means full virtualization: your own kernel and the modules you choose to load into it. lxc, lxc-libvirt or openvz means a container sharing the host kernel. none means bare metal.

The difference bites on a shared kernel. sudo modprobe wireguard fails, and ip link add dev wg0 type wireguard returns RTNETLINK answers: Operation not supported, because a container cannot load a kernel module the host has not loaded. free -h can report host memory instead of yours when lxcfs is missing, so your monitoring reads numbers that are not about your server. Swap is often shared with other containers, and running virtual machines inside your VPS is not possible at all. Container plans are cheaper for a reason, and for a static site or a small application they are still the right buy.

What is the renewal price?

The advertised price often covers the first term only. Look for the words "renews at" on the order page, and for the term length attached to the discount. A discount that lasts one year and a discount locked for the life of the plan are different products behind the same first invoice.

Read the refund terms with the same care. Note how long the money-back window runs, whether it starts at the order or at provisioning, whether add-ons such as extra IP addresses are refundable, and whether an annual prepayment comes back pro rata. Then put a reminder in your calendar a week before the renewal date, because the cheap moment to leave is before the invoice.

Switching later is not free either. Moving a few hundred gigabytes of data, rebuilding the configuration, waiting out DNS (domain name system) time to live values and, for a mail server, rebuilding IP reputation adds up to a full weekend. Count that weekend when a saving looks convincing. What a VPS actually costs over a year is the figure to compare, not the first month.

The thirty minute acceptance test

Run this on the new box before you migrate anything, and while the refund window is still open. Secure it first: the first ten minutes on a new VPS covers the user account, the keys and the firewall. Then install the tools.

sudo apt update
sudo apt install -y sysbench fio ioping sysstat stress-ng vnstat mtr-tiny curl

Check 1: what did they actually give me?

systemd-detect-virt
nproc
lscpu | grep -E 'Model name|MHz|Hypervisor'
free -h
lsblk -d -o NAME,ROTA,SIZE,MODEL
ip -4 addr show scope global
curl -4 -s https://icanhazip.com

You should see the virtualization type, a CPU model, and a memory figure within a few percent of what you bought. free -h reporting far more RAM than the plan sells is a container without lxcfs rather than a bonus. A public address from curl that never appears in ip -4 addr means the IPv4 address is shared.

Check 2: how fast is one thread, and how much steal is there under load?

sysbench cpu --cpu-max-prime=20000 --threads=1 run

Record the events per second line. Single thread speed decides how fast a page renders and how long a build takes, and it is the number cheap plans differ on most. Now load every vCPU and watch what the scheduler actually hands you.

stress-ng --cpu 0 --timeout 300s &
vmstat 1 30
mpstat -P ALL 1 10

--cpu 0 starts one worker per online CPU. Watch the st column in vmstat and %steal in mpstat. Occasional single digits on a shared plan are normal. Steal sitting in double digits for minutes means the physical cores are oversubscribed, so your work is queued behind another tenant. Run sysbench again while the load is on: a single thread score that collapses means your vCPUs are competing with each other, which usually means they are sibling threads on one core rather than separate cores. A low score with near zero steal is the other case, a CPU cap applied by the host, which you cannot see directly from inside the guest.

Check 3: how does the disk behave at queue depth 1?

Run the two fio commands from the NVMe section and keep both results, the 99th percentile latency at queue depth 1 and the IOPS at depth 32. Then check writes, because many volumes are much slower in that direction.

fio --name=wlat --filename=fiotest --size=1G --direct=1 --ioengine=libaio --rw=randwrite --bs=4k --iodepth=1 --numjobs=1 --runtime=30 --time_based --group_reporting
rm -f fiotest

A dd sequential figure is the number a listing likes to quote and the least useful one you can collect, because sequential streaming is not what a database or a busy web application spends its day doing. Collect it if you want the comparison. Decide on the latency.

Check 4: how does the network look from where your users are?

First pull something large down to the VPS.

curl -o /dev/null -w 'in: %{speed_download} bytes/s\n' https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.tar.xz

That tests one path into your server and nothing else. The direction that matters is the one your users take, so serve a file and pull it from a machine near them.

fallocate -l 100M /var/tmp/100mb.bin
python3 -m http.server 8080 --directory /var/tmp

Then, from a laptop or a server close to your audience:

curl -o /dev/null -w 'down: %{speed_download} bytes/s\n' http://YOUR_SERVER_IP:8080/100mb.bin
mtr --report --report-cycles 50 YOUR_SERVER_IP

Port 8080 has to be open in the firewall while you do this, so close it and delete the file afterwards, and stop the Python server with Ctrl+C. In the mtr output, read the loss column on the final line. Loss at an intermediate hop with none at the destination is normal, because routers give the ICMP (internet control message protocol) replies that mtr counts on a low priority, and that is not loss on your traffic. Loss on the last line is real.

Repeat the network test during your users' peak hour. A single sample at 02:00 tells you about a quiet network.

Save all four results in a file with the date, then rerun them in a month. A plan that was fine on day one and slow in week six is a plan whose host filled up, and having the day one numbers is the difference between knowing that and guessing.

When a cheap VPS is the right call

A low price buys real things and costs real things. Older CPUs, a higher oversell ratio, slower network storage, self-service support and thinner redundancy are what make the number small. Match them to the job.

Cheap is correct for a development box, a CI runner, a VPN endpoint, a monitoring node, a backup target or a static site. All of those survive a slow minute. Cheap is a bad trade where latency is the product: a checkout page, an interactive API, a game server or a database that another service waits on. The test above tells you which one you bought, and it tells you while the answer still costs nothing.

FAQ

What does vCPU mean on a cheap VPS offer?

A vCPU is one virtual processor presented to your guest, and it maps to a thread the host scheduler runs on a physical core when it can. It is an allowance to ask for CPU time rather than reserved hardware, unless the listing says "dedicated core" or "dedicated vCPU". Hosts sell more vCPUs than they have cores, and that ratio is rarely published, so measure it. Run stress-ng --cpu 0 --timeout 300s and watch the st column in vmstat 1. Steal sitting in double digits means you are waiting for cores that other guests are using.

Does "unlimited bandwidth" really mean unlimited?

No, and the limit usually lives in two places outside the plan description. The acceptable use policy sets a fair use limit in words, and the port speed sets a hard ceiling in bytes. A 100 Mbit/s port cannot pass more than about 32 TB in 30 days even at full rate, so ask for the port speed and read the policy for the words "fair use" and "sustained". Then track what you really send with vnstat -m and compare it against the allowance.

How can I tell whether my VPS really uses NVMe?

You cannot confirm the physical media from inside a guest, because lsblk only reports what the hypervisor advertises: ROTA of 0 and an empty or generic model string. What you can measure is behaviour. Run fio with --direct=1 at --iodepth=1 and read the 99.00th percentile completion latency. Local NVMe answers in the hundreds of microseconds, and a network attached volume answers in milliseconds even when its sequential throughput looks impressive. Repeat it a few times across the day, since a shared disk is not the same at 03:00 and at 20:00.

What should I test before the refund window closes?

Four things, in this order. What the box actually is, from systemd-detect-virt, lscpu and free -h. Single thread speed, from sysbench cpu --cpu-max-prime=20000 --threads=1 run. Steal time under a full load, from stress-ng --cpu 0 watched with vmstat 1. Disk latency, from fio at queue depth 1. Then measure the network from a machine near your users with mtr and a download of a file you serve from the box. Thirty minutes covers all of it, and doing it before you migrate anything keeps the refund window as leverage.