mod_lsapi is the fastest, lowest-memory way to run PHP on an Apache + CloudLinux cPanel
box without paying for full LiteSpeed Web Server. It ships free with CloudLinux, speaks the
LSAPI protocol directly to lsphp, and pairs with PHP Selector
so each account picks its own version. The catch: the stock config runs in fork-per-request
mode, which throws away most of the speed advantage, and the moment you turn on the
connection pool you start tripping LVE limits if you haven't done the NPROC math first.
This is the tuning guide — which directives actually move the needle, the connection pool
trade-off, and how to keep lsphp workers from generating 508 errors. If you're still
deciding between handlers, read PHP handlers in cPanel compared
first; this assumes you've already chosen LSAPI.
Where the config lives
On a cPanel server the global mod_lsapi config is at:
/etc/apache2/conf.d/lsapi.conf
Per-account and per-directory overrides go in .htaccess (LSAPI honours a subset of
directives there) or in the user's .user.ini. After editing lsapi.conf, apply with a
graceful Apache restart so live requests aren't dropped:
/scripts/restartsrv_httpd --graceful
The connection pool is the big switch
By default mod_lsapi runs with the connection pool off. Every incoming request makes
mod_lsapi connect to the lsphp master process and fork a fresh backend to handle it, then
tear it down. That fork-per-request cost is small per hit but adds up under load and means
OPcache warms cold far more often than it should.
Turn the pool on and lsphp workers stay resident, serving request after request until they
hit an idle timeout or a request ceiling:
lsapi_with_connection_pool On
With the pool on, a warm WordPress page on PHP 8.3 typically returns in single-digit milliseconds of handler overhead instead of the 15–30 ms a cold fork costs. The price is memory and process count: resident workers consume RAM at idle, and — critically — they count against each account's LVE process limits. That second point is where most operators get burned. CloudLinux's own guidance is to enable the pool only for servers with real, sustained PHP traffic (roughly 10+ requests/minute per busy domain); on a box full of idle parked domains, fork-per-request is actually leaner.
Directives that matter
These are the knobs worth touching in lsapi.conf. Defaults shown are CloudLinux's
shipped values.
# Max simultaneous lsphp backend children, server-wide. Default 80.
lsapi_backend_children 80
# How long an idle backend child waits for work before exiting. Default 300s.
lsapi_backend_max_idle 300
# How long the per-user control process lingers idle. Default 30s.
lsapi_backend_pgrp_max_idle 30
# Requests a child handles before recycling (caps memory leaks). Default 10000.
lsapi_backend_max_reqs 10000
# Must match (or exceed) max_execution_time in php.ini.
lsapi_backend_max_process_time 300
# Seconds to wait connecting to the backend before erroring out.
lsapi_backend_connect_timeout 5
How to think about each:
lsapi_backend_childrencaps total concurrentlsphpprocesses across the server. Raise it on a busy multi-tenant box that's queuing requests; lower it on a memory-starved VPS. This is a server-wide ceiling, not per-account — per-account control comes from LVE.lsapi_backend_max_idleis the lever for the pool's memory cost. Higher keeps workers warm longer (faster, more RAM); lower reclaims memory faster (cheaper, more cold starts). On a high-density box, dropping this to 120 is a reasonable middle ground.lsapi_backend_max_reqsrecycles workers to bound memory growth from leaky plugins. The default 10000 is fine; don't set it so low that you're forking constantly.lsapi_backend_max_process_timemust be ≥ your PHPmax_execution_time, or long imports and backups get killed by the handler before PHP's own limit fires. Mismatches here look like random 500s on long-running scripts.
LVE limits: why the pool causes 508s
Here's the interaction nobody documents clearly. CloudLinux's LVE wraps each account in two process-related limits:
- EP (Entry Processes) — concurrent processes entering the LVE, i.e. concurrent PHP requests. Hit it and CloudLinux returns HTTP 508 — Resource Limit Is Reached.
- NPROC — total processes and threads inside the LVE: PHP workers, cron, SSH, everything.
When lsapi_with_connection_pool is On, resident lsphp workers stay alive and keep
occupying NPROC slots even between requests. An account that was comfortable in
fork-per-request mode can suddenly throw 508s under the pool, because warm workers eat the
headroom. CloudLinux enforces a hard rule here: NPROC must be greater than EP + 15 —
LVE Manager warns you if you set it lower, because Apache threads, SSH sessions, and shell
processes all share that NPROC budget.
Practical sequence when you enable the pool:
- Check current limits in WHM → CloudLinux LVE Manager, or:
lvectl list - If you see 508s after enabling the pool, the EP limit is the usual culprit. Raise EP for
the affected package and bump NPROC to keep
NPROC ≥ EP + 15. - Find the offending account with LVE statistics —
lveinfo --period=1dshows EP and NPROC faults per user so you tune the package that's actually hurting, not every package.
For the full picture of how EP, NPROC, PMEM, and IO limits interact — and how to raise them without inviting one account to starve the box — see CloudLinux LVE tuning without angry customers.
A starting config for a busy shared host
For a 16 GB box running 100–200 accounts with real traffic, this is a sane baseline:
lsapi_with_connection_pool On
lsapi_backend_children 80
lsapi_backend_max_idle 120
lsapi_backend_pgrp_max_idle 30
lsapi_backend_max_reqs 5000
lsapi_backend_max_process_time 300
lsapi_backend_connect_timeout 5
Then in LVE Manager, set the default package to something like EP 30 / NPROC 100 and adjust
per-package from lveinfo data. Apply, restart Apache gracefully, and watch
/etc/apache2/logs/error_log plus lveinfo --period=1h for the first hour.
mod_lsapi is bundled with every CloudLinux license tier, so there's no extra SKU to buy for this — it's the highest-leverage free performance win on the platform once the LVE math is right.
FAQ
Does mod_lsapi require a LiteSpeed license?+
Why am I getting 508 errors after enabling the connection pool?+
Should I turn the connection pool on or off?+
Where is the mod_lsapi config file on cPanel?+
What should lsapi_backend_max_process_time be set to?+
Next steps
- Compare LSAPI against PHP-FPM and the deprecated handlers in PHP handlers in cPanel compared
- Get the EP, NPROC, and IO limits right in CloudLinux LVE tuning without angry customers
- Let accounts pick their own PHP version on top of mod_lsapi with the CloudLinux PHP Selector setup guide