PHP-FPM tuning voor WordPress

Leer hoe je PHP-FPM optimaliseert voor WordPress. Praktische tips voor pool-configuratie, worker tuning en betere performance.

11 april 20268 min leestijdDoor We Develop Communication

Elke WordPress-pagina die niet uit cache komt, wordt verwerkt door PHP-FPM. Deze procesmanager bepaalt hoeveel PHP-verzoeken je server tegelijk aankan, hoe snel ze worden opgepakt en hoeveel geheugen ze mogen gebruiken. Toch staat PHP-FPM tuning zelden op de radar bij WordPress-optimalisatie - en dat is zonde, want verkeerde instellingen zorgen voor trage laadtijden, 502-fouten en onnodig hoog geheugengebruik.

In eerdere artikelen behandelden we al hoe je performance bottlenecks herkent en hoe full page caching het merendeel van je requests afvangt. Maar voor alles wat de cache mist - admin-pagina's, WooCommerce-carts, formulierinzendingen, AJAX-calls - is PHP-FPM de schakel die het verschil maakt.

Wat doet PHP-FPM precies?

PHP-FPM staat voor FastCGI Process Manager. Het is de standaard manier waarop NGINX (en steeds vaker Apache) PHP-code uitvoert. In plaats van bij elk verzoek een nieuw PHP-proces te starten, houdt PHP-FPM een pool van workers klaar die verzoeken oppakken zodra ze binnenkomen.

Wanneer een bezoeker een WordPress-pagina opvraagt die niet gecacht is, gebeurt het volgende:

  1. NGINX ontvangt het verzoek en stuurt het door naar PHP-FPM
  2. PHP-FPM wijst het verzoek toe aan een beschikbare worker
  3. De worker laadt WordPress, voert queries uit en genereert de HTML
  4. Het resultaat gaat terug naar NGINX en vervolgens naar de bezoeker

Dit proces beschreven we uitgebreid in wat er tijdens een WordPress request gebeurt. De stap waarin PHP-FPM een worker toewijst is cruciaal: als er geen worker beschikbaar is, moet het verzoek wachten. En wachten betekent een hogere TTFB voor je bezoekers.

De drie process managers: static, dynamic en ondemand

PHP-FPM biedt drie manieren om workers te beheren. De keuze hiertussen heeft direct impact op geheugengebruik en responsiviteit.

Static

pm = static
pm.max_children = 30

Bij static draait er altijd een vast aantal workers, ongeacht of er verkeer is. Het voordeel: er is nooit opstarttijd wanneer een verzoek binnenkomt. Het nadeel: de workers claimen permanent geheugen, ook 's nachts als er niemand op je site zit.

Wanneer kiezen voor static? Bij servers die uitsluitend WordPress draaien en consistent verkeer hebben. Denk aan een drukke WooCommerce-shop waar je weet dat er altijd verzoeken binnenkomen. In een multi-server setup is static vaak de beste keuze, omdat elke server dedicated is.

Dynamic

pm = dynamic
pm.max_children = 30
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 15

Bij dynamic start PHP-FPM met een basishoeveelheid workers en schaalt automatisch op en af op basis van drukte. Dit is de standaardinstelling en voor de meeste WordPress-sites de beste keuze.

  • max_children - het absolute maximum aan workers
  • start_servers - het aantal workers bij het opstarten van PHP-FPM
  • min_spare_servers - het minimum aantal idle workers dat klaar staat
  • max_spare_servers - het maximum aantal idle workers voordat PHP-FPM ze afsluit

Ondemand

pm = ondemand
pm.max_children = 30
pm.process_idle_timeout = 10s

Bij ondemand worden workers pas gestart als er een verzoek binnenkomt, en afgesloten na een timeout zonder activiteit. Dit is zuinig met geheugen maar voegt latentie toe bij het eerste verzoek na een stille periode.

Wanneer kiezen voor ondemand? Op shared hosting of servers waar meerdere sites naast WordPress draaien en geheugen schaars is. Voor productiesites met regelmatig verkeer is dynamic bijna altijd beter.

Het juiste aantal workers berekenen

De belangrijkste instelling is pm.max_children: het maximum aantal PHP-processen dat tegelijk kan draaien. Te weinig workers en verzoeken moeten wachten. Te veel workers en je server raakt door zijn geheugen heen, waardoor de OOM-killer processen gaat afschieten.

Stap 1: Meet het geheugengebruik per worker

Kijk hoeveel RAM een gemiddelde PHP-FPM worker gebruikt op jouw site:

ps -ylC php-fpm --sort:rss | awk '{sum+=$8; count++} END {print "Gemiddeld:", sum/count/1024, "MB"}'

Voor een typische WordPress-site met WooCommerce en een paar plugins ligt dit tussen de 30 en 60 MB per worker. Zware sites met page builders of complexe plugins kunnen oplopen tot 80-100 MB.

Stap 2: Bereken het maximum

De formule is eenvoudig:

max_children = (beschikbaar RAM voor PHP) / (gemiddeld geheugen per worker)

Op een server met 4 GB RAM waar MySQL, NGINX en Redis samen ongeveer 1,5 GB gebruiken, houd je 2,5 GB over voor PHP-FPM. Met workers van gemiddeld 50 MB:

2500 MB / 50 MB = 50 workers

Houd een marge van 20% aan voor pieken in geheugengebruik, waardoor je uitkomt op 40 workers als veilige instelling.

Stap 3: Valideer onder belasting

Theorie is mooi, maar test het in de praktijk. Gebruik een tool als ab (Apache Bench) of wrk om je site te belasten en kijk of workers opraken:

curl -s http://localhost/status?full | grep -E "active|idle|total"

Hiervoor moet je de PHP-FPM statuspage inschakelen (zie verderop).

PHP-FPM statuspage inschakelen

De statuspage is onmisbaar voor het monitoren van je PHP-FPM pool. Voeg dit toe aan je pool-configuratie:

pm.status_path = /status

En in je NGINX-configuratie:

location /status {
    allow 127.0.0.1;
    deny all;
    fastcgi_pass unix:/run/php/php-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

De statuspage toont onder andere:

  • active processes - workers die nu een verzoek verwerken
  • idle processes - workers die klaarstaan
  • listen queue - verzoeken die wachten op een vrije worker
  • max listen queue - de hoogste piek in de wachtrij sinds de laatste herstart

Als listen queue regelmatig boven 0 komt, heb je te weinig workers. Dit is het duidelijkste signaal dat je max_children moet verhogen.

Slow log: trage requests opsporen

PHP-FPM heeft een ingebouwde slow log die een stack trace vastlegt van elke request die langer duurt dan een drempelwaarde:

slowlog = /var/log/php-fpm/slow.log
request_slowlog_timeout = 3s

Na het inschakelen zie je precies welke PHP-functies de vertraging veroorzaken. Vaak wijst dit naar:

  • Trage database queries via wpdb->query()
  • Externe API-calls die op een timeout wachten
  • Zware plugin-logica in wp-cron of admin-ajax.php

De slow log helpt je om gericht te optimaliseren in plaats van blind instellingen te verhogen.

Essentiële php.ini-instellingen

Naast de pool-configuratie zijn er PHP-instellingen die direct invloed hebben op geheugengebruik en stabiliteit:

memory_limit

memory_limit = 256M

Dit is het maximum geheugen dat één PHP-proces mag gebruiken. WordPress raadt minimaal 128 MB aan, maar met WooCommerce en complexe plugins is 256 MB een veiligere keuze. Stel dit niet onnodig hoog in - 512 MB of hoger betekent dat elke worker meer RAM claimt, waardoor je minder workers kunt draaien.

max_execution_time

max_execution_time = 30

De maximale uitvoertijd per request in seconden. De standaard van 30 seconden is voor de meeste WordPress-verzoeken ruim voldoende. Importprocessen of zware cron-taken kunnen een uitzondering zijn - overweeg dan een aparte pool (zie verderop).

opcache

OPcache slaat gecompileerde PHP-bytecode op in het geheugen, zodat PHP niet bij elk verzoek dezelfde bestanden opnieuw hoeft te compileren. Dit is een van de grootste performance-winsten die je kunt behalen:

opcache.enable = 1
opcache.memory_consumption = 256
opcache.max_accelerated_files = 20000
opcache.validate_timestamps = 0

Met validate_timestamps = 0 controleert OPcache niet of bestanden zijn gewijzigd. Dit is sneller, maar je moet OPcache handmatig resetten na een deploy. In productie is dit het waard.

Meerdere pools voor verschillende workloads

Een krachtige maar ondergebruikte functie van PHP-FPM is het draaien van meerdere pools. In plaats van één pool die alles afhandelt, kun je aparte pools configureren voor verschillende soorten verzoeken.

Voorbeeld: apart pool voor wp-admin

; /etc/php/8.3/fpm/pool.d/wordpress-frontend.conf
[wordpress-frontend]
user = www-data
listen = /run/php/php-fpm-frontend.sock
pm = dynamic
pm.max_children = 30
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 15

; /etc/php/8.3/fpm/pool.d/wordpress-admin.conf
[wordpress-admin]
user = www-data
listen = /run/php/php-fpm-admin.sock
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
php_admin_value[memory_limit] = 512M

In NGINX routeer je verzoeken naar de juiste pool:

location ~ ^/wp-admin/ {
    fastcgi_pass unix:/run/php/php-fpm-admin.sock;
    # ... overige fastcgi-configuratie
}

location ~ \.php$ {
    fastcgi_pass unix:/run/php/php-fpm-frontend.sock;
    # ... overige fastcgi-configuratie
}

Waarom is dit waardevol? Admin-gebruikers en zware importprocessen kunnen niet meer alle workers innemen waardoor frontend-bezoekers moeten wachten. Je isoleert de workloads zodat ze elkaar niet bijten.

Monitoring en bijstellen

PHP-FPM tuning is geen eenmalige actie. Je verkeer verandert, plugins worden toegevoegd en geheugengebruik fluctueert. Zorg dat je continu zicht hebt op de gezondheid van je pools.

Waar je op moet letten

  • listen queue > 0 - je hebt te weinig workers, verhoog max_children
  • Geheugengebruik per worker stijgt - een plugin lekt geheugen, stel pm.max_requests in
  • Idle workers constant op max - je verspilt geheugen, verlaag max_spare_servers
  • 502 Bad Gateway fouten - PHP-FPM kon het verzoek niet afhandelen, controleer logs

pm.max_requests: geheugenlekken voorkomen

pm.max_requests = 500

Deze instelling herstart een worker na een bepaald aantal verwerkte verzoeken. Dit is een effectieve maatregel tegen geheugenlekken in PHP of plugins. Na 500 requests wordt de worker afgesloten en een nieuwe gestart, waarmee al het opgebouwde geheugen wordt vrijgegeven.

Zonder deze instelling kunnen workers langzaam groeien in geheugengebruik totdat je server vastloopt. Een waarde van 500 is een goed startpunt - verlaag naar 200 als je merkt dat workers snel groeien.

Voorbeeldconfiguratie voor een 4 GB WordPress-server

Ter afsluiting een complete voorbeeldconfiguratie die als startpunt dient voor een VPS met 4 GB RAM, draaiend op NGINX met MySQL en Redis:

; /etc/php/8.3/fpm/pool.d/wordpress.conf
[wordpress]
user = www-data
group = www-data
listen = /run/php/php-fpm.sock
listen.owner = www-data
listen.group = www-data

pm = dynamic
pm.max_children = 40
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500
pm.process_idle_timeout = 10s

pm.status_path = /status
slowlog = /var/log/php-fpm/slow.log
request_slowlog_timeout = 3s

php_admin_value[memory_limit] = 256M
php_admin_value[max_execution_time] = 30
php_admin_value[opcache.enable] = 1
php_admin_value[opcache.memory_consumption] = 256
php_admin_value[opcache.max_accelerated_files] = 20000

Begin met deze instellingen, monitor de statuspage en slow log en stel bij op basis van wat je ziet. Elke WordPress-site is anders - de juiste configuratie hangt af van je plugins, verkeer en serverresources.

Veelgestelde vragen

Wat is PHP-FPM en waarom is het belangrijk voor WordPress?

PHP-FPM (FastCGI Process Manager) is de procesmanager die PHP-verzoeken afhandelt op je server. WordPress draait volledig op PHP, dus elke pagina die niet uit cache komt, wordt door een PHP-FPM worker verwerkt. De configuratie bepaalt hoeveel verzoeken je server tegelijk aankan.

Hoeveel PHP-FPM workers heb ik nodig voor WordPress?

Een vuistregel is: beschikbaar RAM gedeeld door het geheugengebruik per worker (vaak 30-60 MB). Een server met 4 GB RAM kan typisch 20 tot 40 workers draaien, afhankelijk van je plugins en configuratie. Monitor het werkelijke gebruik om bij te stellen.

Wat is het verschil tussen static, dynamic en ondemand in PHP-FPM?

Bij static draait altijd een vast aantal workers. Bij dynamic start PHP-FPM met een minimum en schaalt op tot een maximum. Bij ondemand worden workers alleen gestart als er een verzoek binnenkomt. Voor WordPress is dynamic meestal de beste keuze.

Hoe weet ik of PHP-FPM de bottleneck is van mijn WordPress-site?

Controleer of je 502- of 504-fouten ziet bij drukte, of je TTFB hoog is terwijl MySQL snel reageert, en of de php-fpm slow log meldingen toont. De PHP-FPM statuspage geeft inzicht in actieve workers, wachtrij en request-duur. Een listen queue boven 0 is een duidelijk signaal dat je meer workers nodig hebt.

Veelgestelde vragen

Klaar om digitaal te groeien?

Wij helpen Nederlandse bedrijven met webtechnologie en SEO-strategieën die écht werken. Neem vrijblijvend contact op.