DocsPHP performance

PHP performance

How ZoPanel fits hundreds of PHP sites on one server: idle PHP that sleeps, always-on PHP, the OPcache file cache, memory compression and load shedding.

On a shared hosting server, most websites are quiet most of the time. ZoPanel uses that: PHP of quiet sites goes to sleep, its compiled code stays on disk so it wakes up fast, idle memory is compressed in RAM, and an overloaded server sheds work it can no longer serve. This page explains each mechanism and the settings that control it.

On our test servers, this let an Ubuntu 24.04 VPS with 4 GB RAM and 4 vCPU run 100 WordPress sites without page cache, or 250 with page cache, each time plus 30 apps. A Debian 12 server with 3 GB ran 50 and 200. After a heavy overload, they were back to normal 2 to 5 minutes after the load stopped.

Idle PHP sleeps

Each hosting account has its own PHP-FPM pool per PHP version. Even with no visitors, a pool's master process uses about 25 MB, so hundreds of quiet accounts would waste gigabytes.

ZoPanel stops a pool once it has had no work for the idle time. The pool's socket stays open, so the next request starts PHP again within a few hundred milliseconds. Visitors do not see an error, only a slightly slower first page.

Set the idle time

  1. Go to Settings → System.
  2. In the PHP performance card, choose Stop idle PHP after: 5, 15 or 30 minutes, 1 or 3 hours, or Never (always running).

30 minutes is recommended and is the default: long enough that a site visited every few minutes is always warm. A shorter time saves memory on crowded servers; Never keeps every site's PHP running.

The card also shows how many pools are running (and how many are always on), the Memory used by PHP, and the size of the Compiled code cache.

A few details:

  • Uptime monitoring requests do not count as visits, so monitoring alone does not keep a quiet site awake.
  • When memory runs short, idle pools are stopped sooner, longest idle first, without waiting for the idle time. Pools that are serving requests are never stopped for this.

PHP always running

For premium plans, turn on PHP always running in the package (Packages → Edit package). Those accounts' pools are started at boot and never stopped for idleness, so no visitor meets a cold start. Each always-on site keeps its pool's memory (about 20-60 MB) even when nobody visits. See Packages and limits.

OPcache file cache

OPcache keeps compiled PHP in memory, which is lost when a pool stops. ZoPanel also keeps each account's compiled scripts on disk, in /var/cache/zopanel/opcache/USERNAME. When a sleeping pool starts again, it loads the compiled code from there instead of compiling every script, so the first request is nearly as fast as a warm one.

Each account's cache folder is private to that account (mode 0700), so no account can read or plant another's compiled code. Scripts not loaded for 30 days, and the folders of deleted accounts, are cleaned up daily.

If the Tuning page reports that OPcache is off for a PHP version, install that version's OPcache package as suggested.

The customer memory plan

ZoPanel divides RAM between the system and customers:

  • The system (databases, mail, nginx, the panel and the kernel) keeps a reserve sized to the machine and to what it actually used at its peak over the last day, and never more than half of RAM.
  • Customers (all PHP pools, apps, shells and Docker apps together) may use the rest, as a hard limit.

The plan is re-calculated every 10 minutes. The PHP performance card shows it: "websites and apps of all customers may use X together; the system keeps Y".

Under a burst that wakes hundreds of sites at once, the kernel throttles or ends customer processes, preferably a PHP worker that restarts at once, while SSH, the panel, nginx and the databases keep working.

Memory compression (zswap)

On Linux 6.8 or newer, ZoPanel compresses customers' idle memory (sleeping PHP masters, OPcache, idle apps) in RAM with zswap, using zstd (or lz4 as a fallback). Compressed pages are never written to disk: what does not fit compressed simply stays in RAM. You get more sites in the same RAM without the disk swapping that makes an overloaded server slow to recover.

It turns on automatically when:

  1. The kernel is 6.8 or newer: Ubuntu 24.04 and Debian 13 out of the box, Ubuntu 22.04 with the HWE kernel the installer adds, Debian 12 with the backports kernel.
  2. The server has a swap device. The installer creates one on servers with less than 4 GB of RAM. If there is none, the Tuning page suggests creating a swap file, with a one-click fix.

Check it on the Tuning page

Go to Tuning (under Server in the menu):

  • Memory compression is on shows the current compression ratio.

  • Kernel X cannot compress customers' memory safely means the kernel is older than 6.8. The suggestion includes the command to install a newer kernel. On Ubuntu 22.04:

    apt install --install-recommends linux-generic-hwe-22.04 && reboot
    

    On Debian 12 (backports kernel, outside Debian's security support):

    echo 'deb http://deb.debian.org/debian bookworm-backports main' > /etc/apt/sources.list.d/backports.list && apt update && apt install -t bookworm-backports linux-image-amd64 && reboot
    

    On ARM64 servers, the Debian package is linux-image-arm64.

Restart the server at a quiet time: websites are offline during the reboot.

Load shedding

When a server is badly overloaded, requests pile up in the PHP sockets faster than PHP can serve them. Most of those visitors have already given up, yet PHP would still run every request, keeping hundreds of pools awake and the server short of memory long after the load is gone.

ZoPanel sheds that work, but only when all of these are true:

  • customers' memory has been badly short for at least a minute (close to the customer limit, or processes waiting for memory 70% of the time);
  • a pool's queue has been full for at least 30 seconds.

The waiting requests of that pool are dropped, at most once per pool per minute. Visitors still waiting get a "This website is very busy right now" page that reloads by itself. The pools can then go idle and free their memory. A server running normally never reaches this point.

Tips

  • Turn on the Page cache (website → PHP & config tab) for WordPress sites: it is the single biggest gain. The Tuning page lists WordPress sites without it and can turn it on for them.
  • Keep the idle time at 30 minutes unless the server is short of memory.
  • Use PHP always running only for the plans that need it.
  • Watch the Tuning page for PHP-FPM that could exhaust the RAM, missing swap and old kernels.

← Packages and limits Optional components →