Why measure before choosing a plan
A client asks "which VPS does my site need?" and the answer is too often a hunch. Two mistakes follow. The first is to take the next plan up "just in case": across a portfolio of twenty clients, that dead margin is paid every month and eats into the agency's margin. The second is to cut it too fine: the first traffic peak, a backup or a catalogue import takes the site down, and the client finds out before you do.
The usual objection is "no time to measure". Yet the measurement takes about an hour of active observation, with tools already present on every Linux distribution. And the first choice is not final: a VPS can be resized vertically, meaning you move to a larger plan without rebuilding the architecture. The goal is not to guess right the first time, but to choose with figures and a written margin that you can defend in front of the client.
The reasoning also applies to a professional running their own site, for example an online shop: the cost of an oversized plan shows on the monthly bill, that of an undersized one in revenue lost during an order peak. The same readings then let you decide with full knowledge, without an intermediary.
This guide covers measurement before purchase and plan selection. To decide between a VPS and shared hosting, read VPS or shared hosting for a client site first. For continuous alerts once the VPS is live, see disk and RAM alerts on a VPS.
What measuring gives you
- A defensible quote — you size the plan from dated readings, not an impression.
- No dead margin — you stop billing or absorbing an oversized plan on every client.
- Fewer outages at the first peak — you see memory saturation coming before it kills a process.
- A baseline for comparison — today's reading lets you judge growth six months from now.
- An honest diagnosis — you tell a site that lacks resources from one that is badly configured.
- A calmer migration — you arrive on the new VPS with a plan already proven against the real load.
Prerequisites: what to prepare before measuring
Measure on the client's current server, the one carrying the real load, not on an empty copy. You need SSH access with read rights, permission to run ps, free and df, and ideally the ability to install the sysstat package, which provides sar and keeps a history of the load.
On duration, plan for at least a week of history if sysstat is already running, otherwise an observation window of at least one hour that deliberately includes a busy moment: a known traffic peak, the nightly backup, a scheduled task or an import. Measuring on a Tuesday at 3 a.m. says nothing about sale day. Finally, note the context: application (WordPress, shop, custom application), presence of containers, database on the same machine or not.
Reading real consumption, step by step
Count the cores
Run
nproc. This number is the reference for reading load: a load average of 4 is healthy on 8 vCPU and critical on 2.Read memory from the right column
Run
free -hand look at theavailablecolumn, notfree. Linux deliberately fills free memory with disk cache that can be reclaimed on demand:freealways looks low, whileavailableshows what is really left for new applications without using swap.Watch CPU, memory and I/O
Run
vmstat 1 10. Watchsiandso(swap exchanges, which should stay at zero),wa(I/O wait) andr(processes waiting for CPU).Read the load average
Run
uptime. The three values are averages over 1, 5 and 15 minutes. Compare them withnproc: a load durably above the number of cores signals waiting.Identify the heavy consumers
Run
ps aux --sort=-%mem | head -15. With containers, adddocker stats --no-stream; with systemd,systemd-cgtopranks services by consumption.Measure disk and inodes
Run
df -hfor space anddf -ifor inodes. A disk can refuse writes while bytes remain free, if inodes are exhausted. Also note the size of the folders that grow: media, database, logs, local backups.Record a history with sar
Install
sysstat, enable collection according to your distribution, then read memory withsar -r, CPU withsar -uand load withsar -q. Without history, sample it yourself:vmstat 60 120produces one reading per minute for two hours.Log the maximum values
Put the memory-used peak, the load peak and the disk growth in a table. That table, not the average, is what you use to compute the plan.
What dominates load by site type
Scroll the table
| Site type | Resource that saturates first | What to record |
|---|---|---|
| Brochure site or low-traffic WordPress | Memory, through PHP and the database | `free -h` at peak, RAM per PHP process |
| Online shop | Memory and CPU during order peaks | Load during a promotion, number of simultaneous PHP processes |
| Business application with a database | Disk I/O and memory | `wa` in `vmstat`, database size, slow queries |
| Media site or image catalogue | Disk and bandwidth | `df -h`, monthly growth of the media folder |
| Site with a heavy import or scheduled task | Occasional CPU and memory | Load and memory during the task, task duration |
| Containerised application | Combined memory of the containers | `docker stats --no-stream`, declared memory limits |
Measure the peak, not the average
A server showing 25% average CPU over 24 hours can be saturated for ten minutes every evening. The average erases exactly what takes a site down. To size, keep the maximum value observed over the window, and check that it contains the worst known moment: traffic peak, backup, heavy cron, import.
If the client does not know when their peaks are, cross-check with the web server access logs and with the dates of email campaigns or promotions. A week of sar history covers a full cycle, weekend included. When the site is already slow, a reading taken during the slowdown is worth more than ten readings taken at rest.
A simple calculation rule, flagged as an assumption
The following rule is editorial, neither a standard nor a catalogue promise: required memory = peak consumption, plus a 30% margin. The 30% figure is this article's assumption; it covers short-term growth and peaks your window did not see. For disk, count used space, plus expected growth over six months, plus at least 20% free.
For a PHP-FPM site, compute the process memory rather than reading it globally: PHP memory = measured RAM per process multiplied by pm.max_children. Measure RAM per process with ps -eo rss,args | awk '/[p]hp-fpm: pool/ {s+=$1; n++} END {print s/n/1024 " MB"}'. The result slightly overestimates, because part of the memory is shared between processes.
Fictional worked example: 600 MB for the system, web server and database, plus 20 processes of 60 MB, that is 1,200 MB, make 1,800 MB at peak. With a 30% margin, about 2.4 GB is needed: choose the plan whose RAM is immediately above that.
Write the margin into the quote
Record in the quote the measured peak, the margin chosen and the date of the reading. When the client asks why this plan and not the next one, the answer is written down. Repeat the reading every six months: a growing site changes plan before it falls over, not after.
Recognise an undersized VPS before the client does
Once the site is in production, a few signals say the plan is too tight. Each leaves a precise trace you can look for without waiting for the client to complain.
The signals, with their exact message
- Process killed for lack of memory — search with
journalctl -k | grep -i "out of memory"ordmesg -T | grep -i "killed process"for a line likeOut of memory: Killed process. The kernel sacrificed a process, often the database. - Active swap — non-zero
siandsoinvmstat 1: the server is swapping memory to disk, and everything slows down. - High I/O wait —
wadurably high intop: the disk or the database is the brake, sometimes for lack of cache in memory. - Load above the number of cores — a load average durably above
nprocmeans processes are waiting their turn. - Saturated PHP-FPM — the line
server reached pm.max_children setting (N), consider raising itin the error log means every process is busy and requests are queuing. - 502 and 504 errors from nginx —
502or504responses, together withupstream timed out (110: Connection timed out), often accompany PHP-FPM saturation. - Full disk or exhausted inodes —
df -handdf -iapproach 100%, and writes fail.
What more RAM does not fix
Before moving up a plan, check that the problem really is a resource question. A slow SQL query saturates the CPU whatever the plan: the missing index gets fixed, it cannot be compensated for. The absence of an object cache forces PHP to recompute the same pages on every visit. An 8 MB image served as is consumes bandwidth and processing time. Finally, raising pm.max_children without raising RAM causes exactly the kill-by-the-kernel you wanted to avoid.
The healthy approach is to fix these points first, take a new reading, then size on the result. That way you avoid billing the client for a bigger plan that only hides a configuration defect.
Choose the plan, then scale up
Once the need is quantified, match it to the range. The VPS Start plan offers 2 vCPU, 4 GB of RAM and 50 GB SSD of storage; the VPS Power plan offers 4 vCPU, 8 GB and 100 GB SSD; the VPS Business plan offers 8 vCPU, 16 GB and 200 GB SSD. Entry price of the range: 99 DH/month.
Choose the smallest plan that covers your need with the written margin, then let vertical scaling do the rest: if the next reading shows the margin melting, you move to the next plan without changing architecture. So you don't wait for that reading, set up continuous alerts, and to know whether the site answers from outside, an availability probe: see availability monitoring for client sites.