Yes, a 4 GB VPS hosting multiple sites requires a fundamentally different resource strategy than a single-site machine because of the cumulative overhead of process pools and database connections. At Hostna, we operate the physical infrastructure to ensure high performance, but the way you distribute the 4 GB of RAM across several environments determines the stability of your stack. When you host one site, the entire innodb_buffer_pool_size and all PHP processes belong to one workload. When you host five, each site competes for the same finite memory pool, often leading to silent failures or the Linux kernel terminating processes to save the system.
| Symptom | Probable Cause | Resolution |
|---|---|---|
| HTTP 502 Bad Gateway | PHP-FPM pool reached pm.max_children |
Increase children or optimize memory_limit |
| MySQL: Out of memory | innodb_buffer_pool_size too high |
Reduce buffer pool to leave room for PHP |
| Site sluggishness | Heavy swapping on NVMe | Check vmstat and reduce process count |
| Process killed | OOM killer triggered | Adjust oom_score_adj or add RAM |
The Math of Multi-Tenancy on a 4 GB Budget
The primary challenge with a 4 GB machine is not the average load, but the peak potential load. If your virtual dedicated server or VPS is running five WordPress sites, each site typically has its own PHP-FPM pool for security isolation. If each pool is configured with pm.max_children = 10 and each PHP process is allowed a memory_limit of 256M, the theoretical maximum memory usage for PHP alone is 12.8 GB. This is significantly higher than the physical 4 GB available on the machine. While sites rarely hit their maximum children simultaneously, a small traffic spike across three sites can easily push the RSS (Resident Set Size) beyond the physical limit.
On our platform, we recommend calculating the “worst-case scenario” by multiplying the total number of allowed child processes across all pools by the average memory usage per process. You can find the average size of a PHP-FPM process on your specific stack by running this command:
ps -ylC php-fpm --sort:rss | awk '{sum+=$8; ++n} END {print "Average RSS: "sum/n/1024" MB"}'
PHP-FPM Tuning for Multiple Pools
When managing multiple sites, the default pm = dynamic setting can be dangerous. Each pool will attempt to maintain a minimum number of spare servers. If you have ten sites, and each maintains pm.min_spare_servers = 2, you have 20 processes idling constantly. In a 4 GB environment, this baseline consumption is significant. A more surgical approach to PHP environment tuning involves using pm = ondemand for low-traffic sites, which kills idle processes immediately, or strictly limiting pm.max_children on the plan you are on.
A PHP-FPM pool with pm.max_children = 10 and a 512 MB memory_limit can claim 5 GB in the worst case, which is why a 4 GB machine that looks idle can still be killed by the OOM killer during one traffic spike — the ceiling is max_children multiplied by memory_limit, not the average usage. To prevent this, you must lower the memory_limit in php.ini to a value that reflects the actual needs of the scripts, such as 128M or 192M, and set pm.max_children based on the remaining RAM after the database and operating system have taken their share.
The Database Bottleneck: MySQL and MariaDB
The database is the largest single consumer of RAM. The innodb_buffer_pool_size directive in /etc/my.cnf dictates how much memory is reserved for caching data and indexes; on a multi-site 4 GB VPS, setting this to 1 GB is often the upper limit before stability degrades. While single-site servers often use three quarters of the RAM for the buffer pool, doing so on a multi-site machine leaves no room for the web server or PHP processes. Furthermore, every additional site adds more table definitions to the table_open_cache and more connection overhead.
If you are hosting WordPress sites, each database connection consumes memory for the thread_stack and various buffers like join_buffer_size and sort_buffer_size. If max_connections is set to 150, and each connection uses 2 MB of buffer space, that is another 300 MB of potential RAM usage. In our shared-hosting tier, these limits are managed for you, but on a VPS, you must manually align these values with your physical memory. Use the following command to check current memory usage by the database:
mysql -e "show variables like 'innodb_buffer_pool_size';"
Understanding the Linux OOM Killer
When the kernel runs out of memory and cannot even reclaim memory from the filesystem cache, it invokes the Out of Memory (OOM) killer. This mechanism selects a process to terminate based on a score. The score is calculated using the process’s memory usage and its oom_score_adj value. On a multi-site VPS, the process with the highest memory usage—usually the database or a heavy PHP-FPM master process—is the first candidate for termination.
To see which processes are currently most at risk, you can inspect /proc/[pid]/oom_score. If you see your database being killed frequently, it is a sign that your PHP-FPM pools are over-provisioned. You can also monitor real-time memory pressure using vmstat 1 to look for “si” (swap in) and “so” (swap out) activity. If these numbers are consistently high, your NVMe drive is being used as RAM, which will drastically increase your Time to First Byte (TTFB) and overall latency.
Identifying the Resource-Hungry Site
One of the hardest parts of running multiple sites on one 4 GB VPS is identifying which specific site is causing a spike. Standard tools like top show all php-fpm processes under the same name. To differentiate them, use htop and enable the “User” column, ensuring each site runs under its own Linux user. This isolation is a standard security practice that also provides clear resource accounting. If site A is consuming 2 GB of RAM while sites B, C, and D are idling, the dashboard in the control panel will show high usage, but only htop or nmon will tell you where to look.
You can also use ps to see the exact memory usage of every process in a human-readable format:
ps -eo size,pid,user,command --sort -size | awk '{ hr=$1/1024 ; printf("%13.2f Mb ",hr) } { for ( i=4;i<=NF;i++ ) { printf("%s ",$i) } print "" }'
This command helps you identify if a specific site has a memory leak or an inefficient plugin. If you find that one site consistently requires more than its share, it may be time to consider dedicated hardware resources or at least a larger VPS plan.
Noisy Neighbors Within Your Own Server
On a 4 GB VPS, you are your own “noisy neighbor.” A backup script running on site A can starve site B of the CPU and RAM it needs to serve requests. This is especially true for Linux distribution choice where default cron jobs might include heavy tasks like updatedb or mandb. To mitigate this, you can use cgroups to limit the memory usage of specific PHP-FPM pools, ensuring that site A can never take more than 1 GB, regardless of how many requests it receives.
For those running automation workloads alongside websites, the memory pressure is even more acute. Automation tools often have a high baseline memory footprint. If your account includes such tools, you must account for their RSS before allocating memory to your web server and database. The Hostna infrastructure is designed to handle these loads, but the internal allocation remains your responsibility as the server administrator.
When 4 GB Is Not Enough
If you find that you are constantly tuning pm.max_children downward to the point where your sites are returning 503 errors because no processes are available, you have reached the limit of a 4 GB VPS. The most reliable way to scale is to either move the database to a separate instance or upgrade the existing machine. Adding swap space can prevent the OOM killer from firing, but it is not a performance solution; swap is thousands of times slower than RAM, even on modern NVMe storage.
Before upgrading, ensure that opcache.memory_consumption is set appropriately. This setting is defined in the PHP-FPM configuration documentation and determines how much memory is used to store precompiled script bytecode. On a 4 GB machine with multiple sites, allocating 128 MB to 256 MB for OpCache across all pools is usually sufficient. If you exceed this, PHP will have to recompile scripts on every request, which spikes CPU usage and slows down the site.
If your tuning efforts do not stabilize the machine, gather the output of free -m, top -b -n 1, and the last 50 lines of /var/log/syslog (or /var/log/messages) and send them to support via the dashboard. This data allows us to see if the issue is related to the underlying hypervisor or internal resource exhaustion.
This article was drafted with AI assistance from Hostna’s own research pipeline and published without individual review. Tell us if anything here is wrong.
