The PHP handler dropdown in Plesk has more entries than cPanel's, and the two that matter
most — FPM application served by nginx and FPM application served by Apache —
look almost identical in the UI. They are not. One is roughly twice as fast on the request
hot path and breaks every WordPress site that ships an .htaccess. The other is the safe
default and the reason most Plesk hosts cap out at lower req/s than they should.
This is what each handler actually does on a Plesk Obsidian box, what it costs in RAM,
where it breaks, and which one to pick by workload. Everything below assumes you are
running the Plesk PHP packages (plesk-php83,
plesk-php82, etc.) — not a hand-rolled remi or sury install, which Plesk will refuse to
manage from the UI.
At a glance
| Handler | Memory per idle site | First-request latency | .htaccess works | File ownership | Best for |
|---|---|---|---|---|---|
| FPM by nginx | ~25–50 MB | ~10–30 ms | No | Subscription user | Laravel, Symfony, static-heavy sites, API backends |
| FPM by Apache | ~25–50 MB + Apache worker | ~20–50 ms | Yes | Subscription user | WordPress, Joomla, Drupal, anything you didn't write |
| FastCGI (mod_fcgid) | ~15–30 MB per active site | ~40–80 ms | Yes | Subscription user | Constrained boxes where FPM tuning is unrealistic |
| CGI (mod_cgi + suexec) | ~0 MB at idle, fork per request | ~150–400 ms | Yes | Subscription user | Legacy CGI/Perl-style scripts only |
| Apache module (mod_php) | Shared with Apache prefork | ~10–20 ms | Yes | apache / nobody | Nothing — avoid on multi-tenant boxes |
The short version: FPM by Apache is the right default for any subscription you didn't write. Switch to FPM by nginx when the application has its own routing layer and you control its config. Treat the other three as legacy or transitional.
FPM application served by nginx
This is the "pure" path. Nginx terminates the request and proxies straight to PHP-FPM over
a Unix socket. There is no Apache in the chain. The pool config lives at
/etc/php-fpm.d/plesk-phpXX-fpm-domain-N.conf on RHEL-family hosts, or
/etc/php/X.Y/fpm/pool.d/ on Debian/Ubuntu, and looks like:
[domain123]
listen = /var/www/vhosts/system/example.com/php-fpm.sock
listen.owner = example_com
user = example_com
group = psacln
pm = ondemand
pm.max_children = 5
pm.process_idle_timeout = 60s
The latency win comes from removing Apache: no .htaccess parse, no MPM worker dispatch,
no second proxy hop. On a typical WordPress request hot path you save 15–25 ms per request
and roughly half the resident memory.
The cost is that nginx does not read .htaccess. Every rewrite rule, deny block,
header override, and security plugin's IP allowlist has to be translated into nginx syntax
and pasted into Apache & nginx Settings → Additional nginx directives for the domain.
WordPress's stock rewrite block becomes:
location / {
try_files $uri $uri/ /index.php?$args;
}
That is the easy case. A Wordfence or All-in-One Security plugin spraying 80 lines of
mod_rewrite and mod_headers rules into .htaccess is the hard case, and the failure
mode is silent — the site appears to work, but the WAF and the redirects don't run.
FPM application served by Apache
The default Plesk picks for new subscriptions. The chain is nginx (frontend reverse proxy
serving static files) → Apache (httpd) → PHP-FPM via mod_proxy_fcgi. Apache reads
.htaccess on every PHP request, which is where the latency cost comes from — but it also
means every mod_rewrite, mod_headers, and mod_deny rule your CMS or your plugin emits
just works.
For a multi-tenant Plesk box hosting agency sites you didn't build, this is the only
defensible default. The combined nginx-static + Apache-dynamic split means you still get
nginx's static-file performance for /wp-content/uploads/*.jpg, while PHP requests get
the full Apache compatibility surface.
The pool tuning is identical to FPM-by-nginx — same files, same knobs. The Apache layer
adds one httpd worker per active request, ~5–15 MB each. On a 4 GB VPS that's the
difference between 80 and 120 sustained PHP-serving sites.
FastCGI application (mod_fcgid)
The pre-FPM Plesk default, kept around for compatibility. Each request forks a new PHP
process under suexec; Apache reuses the process for a configurable number of subsequent
requests via mod_fcgid before killing it. Memory per active site is lower than FPM
(~15–30 MB) because there are no warm idle workers, but request latency is higher and the
fork rate is brutal under sudden load spikes — exactly the failure mode that drove the
shift to FPM.
Pick FastCGI only when:
- You have hundreds of mostly-idle subscriptions on a memory-constrained box and per-pool FPM tuning would burn admin hours you don't have.
- You hit a specific PHP extension that misbehaves in long-lived FPM workers (rare; most fixes are upstream now).
Otherwise FPM-by-Apache wins on every axis.
CGI application
mod_cgi with suexec. Forks a fresh PHP process per request, no reuse. Latency is
150–400 ms minimum because of the fork-and-exec on every hit. Use it for one specific
case: a subscription running pre-2010 Perl-style CGI scripts that assume each invocation
gets a clean process. Otherwise this handler exists to make a comparison table complete.
Apache module (mod_php)
mod_php loads PHP into the Apache worker. Lowest per-request overhead, no fork, no IPC.
The catch is that every PHP request runs as the Apache user (apache on RHEL,
www-data on Debian) — not the subscription user. That means:
- Files PHP writes are owned by
apache, breaking quota accounting and any user-level ownership check. - One vulnerable site can read every other site's files on the same Apache instance.
- Plesk's PHP Selector (per-domain PHP version) does not work, because mod_php is a single loaded module per Apache.
mod_php was deprecated as the default in Plesk Obsidian and removed from the dropdown for new domains in Obsidian 18.0.55+. If you see it on an old subscription, switch it to FPM-by-Apache and don't look back. There is no shared-hosting case where mod_php is the right answer.
Switching the handler
In the UI: Subscriptions → example.com → PHP Settings → PHP support → PHP version. The handler dropdown is directly below the version picker. Changes apply on save with no downtime — the next request uses the new handler.
From the command line:
plesk bin php_handler --list
plesk bin domain --update -domain example.com -php_handler_id plesk-php83-fpm
Handler IDs follow the pattern plesk-phpXX-{fpm,fpm-apache,fastcgi,cgi,module}. The
fpm ID is FPM-by-nginx; fpm-apache is FPM served by Apache. This trips people up — the
short name fpm is the more aggressive choice.
Pool tuning that actually matters
For both FPM handlers, the three knobs that decide RAM behavior are the same as on cPanel (see PHP-FPM pool tuning on cPanel for the math — it ports directly):
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 30s
Plesk exposes pm, pm.max_children, pm.max_requests, and a handful of others under
PHP Settings → Performance Settings as named fields. Anything else (pm.start_servers,
request_terminate_timeout, custom php_admin_value directives) goes into Additional
configuration directives at the bottom of the page, which Plesk merges into the pool
file on save.
Recommendations by workload
- WordPress, WooCommerce, Joomla, Drupal, generic CMS hosting: FPM by Apache. The
.htaccesscompatibility is non-negotiable for sites managed by plugins. - Laravel, Symfony, Statamic, custom PHP frameworks with front-controller routing: FPM by nginx. You already write the rewrites, you'll save ~20 ms per request.
- API backends, headless WordPress, REST/JSON endpoints: FPM by nginx. Latency wins compound at scale.
- Static-heavy marketing sites with one PHP contact form: FPM by Apache. The handler rarely runs, simplicity wins.
- Legacy shared box you inherited: FPM by Apache, then audit the slowest 10 subscriptions and consider tuning their FPM pools individually.
- Anything currently on mod_php: migrate to FPM by Apache. Today.
For multi-tenant hosts running CloudLinux, the answer changes slightly — CloudLinux's PHP Selector replaces Plesk's PHP version handling and adds LVE limits per subscription. That's covered in CloudLinux PHP Selector setup.
What is the difference between FPM served by nginx and FPM served by Apache in Plesk?+
Is mod_php still available in Plesk Obsidian?+
Why is my WordPress site broken after switching to FPM by nginx?+
Can I run different PHP handlers for different subscriptions on the same Plesk server?+
Which PHP handler uses the least RAM in Plesk?+
How do I switch all subscriptions on a Plesk server to FPM at once?+
Next steps
- Plesk license tiers explained — which edition unlocks which handlers and per-domain PHP version control.
- Tune PHP-FPM pools on cPanel — the pool math ports directly to Plesk; same knobs, same trade-offs.
- CloudLinux PHP Selector setup — when you outgrow Plesk's built-in PHP version handling and need per-user LVE limits.