You just pushed a fresh WordPress launch for a local boutique, enabled HTTPS, and pointed the domain at your TrueCore nameservers. The browser reports a Time To First Byte of 190 ms, even though no CDN sits in front of the site. That is the result of a handful of server-level choices we make for every plan.
Measuring the real server cost
TTFB is the interval between the moment the client opens a TCP connection and the moment it receives the first byte of HTML. It excludes the time the user's ISP or home Wi-Fi spends routing packets. In our monitoring tools a value under 200 ms signals that the web stack, database and OS all responded quickly enough that the network becomes the next bottleneck.
When we first added the metric to our internal dashboards, we saw many customers sitting between 250 ms and 600 ms even on fresh SSD nodes. The difference was not the hardware - all three of our nodes run Alpine 3.19.9 (ember) or 3.23.4 (spark, litespeed) with Linux 6.6.117 or 6.18.x kernels - but the way the software stack handled each request.
PHP-FPM tuned for low latency
PHP-FPM is the process manager that runs your WordPress code. It applies to our Ember plan and up; Flameling is static-only hosting with no PHP, so the tuning below is for PHP-capable plans. By default many hosts leave the settings at the generic distribution values, which can cause workers to queue when traffic spikes.
At TrueCore we set the following directives in /etc/php/8.3/fpm/pool.d/www.conf:
pm = dynamic
pm.max_children = 30
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
request_terminate_timeout = 30s
rlimit_files = 1024
dynamiclets the manager grow and shrink based on demand, avoiding a permanent pool of idle workers that waste RAM.pm.max_childrenmatches the memory budget of our PHP-capable plans (Ember and up, e.g. 40 GB on Ember), keeping the total PHP RAM usage under 1.5 GB per node.- The spare server parameters keep at least five ready workers at all times, which eliminates the "Waiting" phase that Chrome DevTools records as part of TTFB.
When we restart the pool (site restart php) the new limits take effect immediately. The result is a consistent 10-20 ms drop in the waiting time for the first request, because the scheduler never has to fork a new PHP process under load.
OPcache, sendfile and static asset handling
We enable OPcache on every account as described in our earlier post about the biggest WordPress performance win. The key settings are:
opcache.enable=1
opcache.memory_consumption=256
opcache.validate_timestamps=1
With 256 MiB of shared memory, the compiled bytecode for a typical WordPress core plus a moderate plugin set stays resident, so the PHP interpreter can skip the parse-compile cycle on every request.
For static files (CSS, JS, images) we let nginx use the sendfile system call. The directive in our nginx.conf looks like this:
sendfile on;
tcp_nopush on;
tcp_nodelay on;
sendfile moves data from the filesystem cache to the network socket entirely in kernel space, bypassing user-space copies. On our Alpine (an independent musl/BusyBox distro) nodes the kernel's page cache holds the most frequently requested assets, so the OS can satisfy the request in under 5 ms.
We also enable HTTP/2 multiplexing, which reduces the round-trip overhead for the first HTML packet. Combining OPcache, sendfile and HTTP/2 means the server can start streaming data before the PHP worker even finishes building the page.
Cgroup limits protect against noisy neighbours
All three of our nodes run the custom isolation layer flame-bubble, which wraps each site in a bwrap sandbox and applies cgroup limits for CPU and I/O. The relevant slice looks like this:
/sys/fs/cgroup/unified/site123/
cpu.max = 50000 100000
io.max = rbps=10485760 wbps=10485760
The CPU limit caps the site at 50 % of a single core, preventing a poorly coded plugin from hogging the processor and delaying other sites. The I/O limit restricts reads and writes to 10 MiB/s, which stops a backup job from flooding the disk queue.
Because the limits are enforced by the kernel, they do not add noticeable latency to a well-behaved site. Instead, they keep the average TTFB stable across all accounts on the node, even when one customer runs a heavy cron job.
What we don't do: rely on a CDN for TTFB
A CDN can shave a few milliseconds off the network leg, but it does not change the time the origin server spends generating the first byte. Our approach removes the need for a CDN when the goal is raw server speed. We still recommend a CDN for static asset off-loading and global reach, but the core WordPress experience remains sub-200 ms without any third-party edge.
Trade-offs you should know
- The CPU cgroup limit means a single site cannot use more than half a core at once. If a site needs sustained full-core processing (e.g., video transcoding), you should move that workload to a dedicated VM.
opcache.validate_timestampsadds a tiny check on each request. Disabling it would shave a fraction of a millisecond but would require manual cache clears after any code change.sendfileworks best when the underlying storage is not saturated. Our nodes use SSD storage provided by Netcup, RackNerd and eVPS.net, which comfortably handles the typical read rates for WordPress sites.
Bottom line
By keeping PHP-FPM workers ready, letting OPcache hold compiled bytecode, using sendfile for static files, and isolating each site with kernel-enforced cgroup limits, we consistently see TTFB values between 120 ms and 190 ms for UK sites on our Ember and Blaze plans. The numbers come from real measurements on our three-node fleet - Nuremberg (ember), Sofia (spark) and Dallas (litespeed). No CDN, no magic, just a tightly tuned stack that respects the limits of shared infrastructure.
If you're on a plan that still reports TTFB above 200 ms, start by checking the PHP-FPM pool size and confirming that OPcache is active (phpinfo() shows the OPcache section). A quick restart of the PHP service often aligns the configuration with the current memory budget and brings the latency back into the sub-200 ms range.