The first hour on a new VPS: four promises of the plan and the commands that verify them

The server is paid for, a root password email has arrived, and hands itch to install the panel. Stop. Right now you have something you won’t have in a week: an idle machine with no load and a live return window — hourly billing or a guarantee for a few days. On an empty machine, measurements are honest, and the decision “this server isn’t a fit” costs pennies. In a week there will already be a node with users on it, and you’ll tell yourself that an 8% steal is normal.

Below are four promises that were sold to you in the tariff card, and how to verify each one. In total it’s about twenty minutes, not counting fio.

Important:

All measurements are taken before load is sent to the server. Not because it’s neater, but because otherwise you’ll be measuring yourself: a built-in Xray in the background will show steal-like load and garbage in the iperf3 output.

The Zero Promise: what kind of machine is this anyway

The word “VPS” is marketed both as a full virtual machine and as a container on a kernel shared with hundreds of neighbors. The difference isn’t cosmetic: in the second case, half of what you planned to do is physically unavailable.

systemd-detect-virt

The command prints the type of virtualization and exits with code 0 if virtualization is detected, and non-zero if the machine is physical. kvm is a full VM. lxc, lxc-libvirt, openvz, podman are containers. If both layers are nested, the inner is shown by default; you can distinguish them with --vm and --container.


Diagram based on the documentation systemd-detect-virt and linuxcontainers.org

The goal of LXC, as the project itself formulates it, is to “create an environment as close as possible to a regular Linux installation, but without needing a separate kernel.” There is no separate kernel — which means no modprobe. The kernel WireGuard (in mainline since 5.6) won’t boot, sysctl for the network stack is either read-only or changes across the host and you won’t be allowed to modify it, and nproc will show the host’s cores, not yours.

Warning:

Containerized “VPS” isn’t always a trick. For $2–3 it’s a fair format, and it works for static sites, bots, or mirrors. But if you bought a machine for a node with kernel WireGuard, for your own tcp_bbr, or anything that requires kernel modules, that’s not the product, and you should figure it out now, not in a month.

Meanwhile, check what’s up with the TUN device — without it no tunnel will run:

ls -l /dev/net/tun

The Promise of “2 vCPU”: how many of them are really yours

vCPU isn’t a core, it’s a share of time on a core that the hypervisor allocates to you. How much it takes is visible in the steal counter.

vmstat 1 10

The st column in the output, by definition from the man page, is the “time stolen from the virtual machine” (until Linux 2.6.11 it wasn’t even counted). The primary source of the counter is the eighth field of the cpu line in /proc/stat, and the kernel docs describe it briefly: involuntary wait, forced waiting. This is the time when your task was ready to run, but the physical core was given to a neighbor.

What you see in st How to read it
0–1 % Normal. No over-scheduling, or neighbors are idle
2–5 % Acceptable for a web server, noticeable for a TLS proxy node
5–15 % Core is shared tightly; latency will increase under load
> 15 % consistently You’re paying for a share you don’t get

Thresholds are practical guidelines, not standards: there is no legal “acceptable steal” in the official docs, and the same percentage feels different on a batch task vs. interactive traffic. More important is not the per-second number, but whether it holds for ten minutes and repeats at different times of day.

Info:

The neighboring wa (iowait) column on a VM is not worth taking seriously. The kernel docs say plainly: “iowait unreliable when reading from /proc/stat” — the value can even go down, and on a many-core machine it’s hard to compute correctly. Disk is measured not by wa, but with fio — see below.

For a TLS node, separately check whether the hypervisor exposed hardware AES:

grep -o -m1 -E 'aes|avx2' /proc/cpuinfo
openssl speed -evp aes-128-gcm -seconds 3

openssl speed is the standard tool for measuring crypto algorithm speeds, -evp runs the cipher through the EVP interface. The difference between AES-NI and software implementation isn’t in percentages, but in repetitions, and on a proxy host it translates directly into throughput. If the aes flag isn’t present in /proc/cpuinfo, and the tariff was sold as “VPN-ready”, that’s a reason to ask support.

The Promise of “NVMe”: why dd doesn’t measure anything here

Classic “test disk with dd, it’s fast” does not test the disk. dd if=/dev/zero of=test bs=1M count=1024 writes linearly and fills the page cache, and on someFSes zero blocks may also collapse. You’ll get host memory speed, not storage.

Error:

dd, hdparm -t and “downloaded a file, speed good” are not disk benchmarks. None of them create realistic I/O load with a queue, and that is what kills databases and the panel logs. Measure fio with --direct=1.

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

What matters here. --direct=1 enables non-buffered I/O (O_DIRECT) — requests go past the page cache, and you see the storage, not memory. --bs=4k with --rw=randread gives random reads in 4 KB blocks: this is the database/profile, not movie copying. --iodepth=32 keeps the queue, --time_based runs the load for the full 60 seconds, even if 1 GB is read earlier.

Two things to look for in the output: IOPS and the tail latency clat percentiles. The average latency lies — what matters is the 99th percentile. A disk that delivers good IOPS with a p99 in the hundreds of milliseconds is a disk that will sometimes make the panel pause in front of users. By the way, if you’ve run into the issue of suddenly running out of space for containers, the reason is usually not the disk: where /var/lib/docker really goes.

The Promise of “1 Gbit/s”: how far does it actually go

In the tariff card, the port speed is stated. The port is the first mile of the path.


Diagram based on iperf3 documentation and practical network diagnostics

The test “download our file from a neighboring server” that many hosts offer honestly shows that the virtual adapter works — and nothing more. A useful test starts with a public iperf3 in another country:

apt install -y iperf3
iperf3 -c ping.online.net -p 5200 -t 20        # upload
iperf3 -c ping.online.net -p 5200 -t 20 -R     # download (reverse)

Public servers are listed at iperf.fr, and there is a caveat there that saves half an hour of confusion: the server handles only one connection at a time. If it’s busy, use a neighboring port from the range or another site. Be sure to run both directions: the asymmetry “uploads at 900, downloads at 80” is a typical sign of a congested uplink.

Next — route:

mtr -rwzbc 100 1.1.1.1
Warning:

Packet loss on intermediate hops in mtr by itself means nothing. Many routers intentionally deprioritize ICMP responses to their own address — transit traffic is sent with no loss. The diagnosis is only on the last line: if there is loss on the fifth hop and none on the final, all is fine.

Also check MTU if there will be a tunnel on the server:

ping -M do -s 1472 1.1.1.1
```There is an error in my update

```ruby
api_key = "a quick brown fox"
fetch("https://api.example.com/data", headers: { 'Authorization' => api_key })

Please help me fix it.