Kort gezegd: PHP-FPM (FastCGI Process Manager) draait PHP als eigen dienst naast de webserver. Een masterproces beheert pools, en elke pool start workers die verzoeken via FastCGI afhandelen. Pools kunnen per website worden gedraaid met eigen gebruiker, eigen grenzen en vergrendelde PHP-instellingen. Omdat workers veel verzoeken na elkaar afhandelen, moeten ze na een PHP-update allemaal opnieuw worden gestart.
Wat is PHP-FPM?
De PHP-handleiding beschrijft FPM als de primaire FastCGI-implementatie van PHP met functies die vooral nuttig zijn voor zwaar belaste websites. FPM werd met PHP 5.3.3 als eigen SAPI opgenomen, dus als eigen uitvoeringsmodus. De SAPI-naam is fpm-fcgi.
Het verschil met mod_php: PHP draait niet in de webserver, maar als eigen dienst. Nginx, Apache of een andere webserver geeft PHP-verzoeken via het FastCGI-protocol door en krijgt het kant-en-klare antwoord terug. Webserver en PHP kunnen daardoor onafhankelijk van elkaar opnieuw worden gestart, geconfigureerd en beveiligd. Hoe FastCGI in principe werkt, staat onder CGI en FastCGI.
Master, pools en workers: het procesmodel
PHP-FPM bestaat uit drie niveaus:
- Masterproces: leest de configuratie, opent de sockets en start of beëindigt workers. Hij voert zelf geen toepassingscode uit.
- Pools: Elke pool heeft een naam, een eigen socket of poort, een eigen Unix-gebruiker en eigen PHP-instellingen. De handleiding noemt uitdrukkelijk verschillende uid, gid, chroot, omgeving en php.ini per pool.
- Workers: processen van een pool die verzoeken aannemen en uitvoeren. Een worker handelt veel verzoeken na elkaar af voordat hij wordt vervangen.
Hoeveel workers draaien, bepaalt de procesmanager met de directive pm:
| Modus | Gedrag | Belangrijke directives |
|---|---|---|
static |
vast aantal workers | pm.max_children |
dynamic |
workers tussen onder- en bovengrens | pm.start_servers, pm.min_spare_servers, pm.max_spare_servers |
ondemand |
workers pas bij behoefte, afbouw na inactiviteit | pm.process_idle_timeout (standaard 10s) |
pm.max_children beperkt in alle modi het aantal gelijktijdige verzoeken. pm.max_requests vervangt een worker na een vast aantal verzoeken; de standaardwaarde 0 betekent onbeperkt.
Welke modus past, hangt af van de belasting. static houdt altijd evenveel workers klaar en is geschikt voor gelijkmatig zwaar gebruikte toepassingen met genoeg werkgeheugen. dynamic is een compromis voor de meeste websites. ondemand bespaart geheugen op servers met veel kleine websites, omdat pools zonder bezoekers geen workers bezetten; daarvoor duurt het eerste verzoek na een pauze iets langer. Een te hoog ingestelde pm.max_children kan de server bij belastingpieken in geheugentekort jagen, een te lage leidt tot wachttijden en foutmeldingen van de webserver.
Een pool met veilige basisinstellingen
Een voorbeeld van een eigen pool per website, met directives uit de PHP-handleiding. Paden en waarden zijn voorbeelden:
; /etc/php/8.3/fpm/pool.d/kunde-a.conf
[kunde-a]
user = kunde-a
group = kunde-a
listen = /run/php/kunde-a.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 10s
request_terminate_timeout = 60s
security.limit_extensions = .php
clear_env = yes
php_admin_value[open_basedir] = /var/www/kunde-a:/tmp
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[error_log] = /var/log/php/kunde-a.error.log
Volgens de handleiding kunnen waarden via php_value en php_flag tijdens de uitvoering met ini_set() worden gewijzigd, waarden via php_admin_value en php_admin_flag daarentegen niet. security.limit_extensions staat standaard op .php .phar en bepaalt welke bestandsextensies FPM als hoofdscript uitvoert. clear_env = yes is de standaard en leegt de omgeving van de workers.
Voor bewaking is er een statuspagina via pm.status_path en een pingpagina via ping.path. Beide mogen alleen intern bereikbaar zijn. Trage verzoeken legt FPM vast met backtrace, als request_slowlog_timeout en slowlog zijn ingesteld.
De PHP-handleiding waarschuwt: wie een FastCGI-verbinding met PHP-FPM kan openen, beheerst de configuratie van het verzoek en kan daarmee willekeurige code uitvoeren. PHP-FPM mag nooit bereikbaar zijn vanuit een niet-vertrouwd netwerk. Gebruik een Unix-socket of listen.allowed_clients.
Welke rol speelt PHP-FPM bij PHP2Shell?
PHP-FPM hoort bij de getroffen uitvoeringsmodi. Het procesmodel wordt vooral duidelijk bij CVE-2026-109619: de interne toestand die bij het verzoek hoort, kan na het vrijgeven van het geheugen blijven bestaan, en een later verzoek in dezelfde worker kan die gebruiken voordat hij wordt teruggezet. Dat is alleen mogelijk omdat workers veel verzoeken na elkaar afhandelen.
Hieruit volgen drie verplichtingen:
- Update installeren: PHP 8.5.12, 8.4.27, 8.3.36 of 8.2.35, dan wel een bevestigde backport van de distributie.
- Alle workers opnieuw starten: Nieuwe bestanden op de schijf veranderen niets zolang oude workers draaien. Dat geldt voor elke geïnstalleerde FPM-versie en elke pool. De opdrachten staan onder PHP-FPM en alle workers opnieuw starten.
- Tussenwaarden vergrendeld instellen: De maatregelen van php.net, bijvoorbeeld
session.upload_progress.enabled=0, horen viaphp_admin_valueofphp_admin_flagin de pool, niet in.user.ini.
De scheiding in pools vervangt geen update, maar beperkt de schade: draait elke website onder een eigen gebruiker, dan bereikt een aanvaller na een inbraak niet automatisch de bestanden van de andere. Hoe dat er concreet uitziet, beschrijft PHP-FPM-pools per website isoleren; de inbedding in Nginx staat onder Nginx met PHP-FPM beveiligen.
Hoe helpt PHP SOS concreet?
- Pools in kaart brengen: Wij sommen alle FPM-versies, pools, gebruikers en sockets van uw server op.
- Patchen en herstarten: Wij werken PHP bij en bewijzen aan de hand van starttijden dat er geen oude worker meer draait.
- Pools scheiden: In het kader van de serverhardening richten wij per website een pool in met eigen gebruiker en vergrendelde instellingen.
- Bereikbaarheid controleren: Wij controleren dat FastCGI-sockets en statuspagina's niet van buitenaf bereikbaar zijn.
Veelgestelde vragen
Waar staat FPM voor?
FPM staat voor FastCGI Process Manager. De PHP-handleiding beschrijft hem als de primaire FastCGI-implementatie van PHP met functies die vooral nuttig zijn voor zwaar belaste websites. Hij werd met PHP 5.3.3 opgenomen.
Wat is het verschil tussen pool en worker?
Een pool is een groep workerprocessen met gemeenschappelijke configuratie: gebruiker, socket, grenzen en PHP-instellingen. Een worker is één enkel proces dat verzoeken na elkaar afhandelt. Een server kan veel pools hebben, bijvoorbeeld één per website.
Moet PHP-FPM bereikbaar zijn via TCP of via een Unix-socket?
Draait de webserver op dezelfde host, dan adviseert de PHP-handleiding een Unix-socket. Bij TCP moet listen.allowed_clients worden ingesteld, omdat anders elk adres mag verbinden. Een openlijk bereikbare FastCGI-poort staat volgens de handleiding willekeurige code-uitvoering toe.
Beschermt pm.max_requests tegen lekken als PHP2Shell?
Nee. pm.max_requests vervangt een worker na een vast aantal verzoeken en helpt vooral tegen geheugenlekken in extensies. Tegen een lek in de interpreter helpt alleen de update met aansluitend een herstart van alle workers.