# PHP-FPM selitettynä: prosessinhallinta, poolit ja workerit

> PHP-FPM selitettynä: miten master, poolit ja workerit toimivat, mitä pm static, dynamic ja ondemand tarkoittavat ja mitkä asetukset lisäävät tietoturvaa.

Lähde: https://phpsos.de/fi/php/php-fpm-erklaert/  
Tilanne: 25.10.2026  
Palveluntarjoaja: PHP SOS, PHP-hätäapu ja palvelimen tietoturva. Pikaapu WhatsAppilla: https://wa.me/491736494914?text=Hei%20PHP%20SOS%2C%20tarvitsemme%20apua%20PHP-palvelimemme%20kanssa.%20Yritys%3A%20%E2%80%A6%20Verkkosivusto%3A%20%E2%80%A6

**Lyhyesti:** PHP-FPM (FastCGI Process Manager) ajaa PHP:tä omana palvelunaan verkkopalvelimen rinnalla. Master-prosessi hallinnoi pooleja, ja jokainen pooli käynnistää workereita, jotka käsittelevät pyyntöjä FastCGI:n kautta. Pooleja voi ajaa verkkosivustokohtaisesti omalla käyttäjällä, omilla rajoilla ja lukituilla PHP-asetuksilla. Koska workerit käsittelevät monta pyyntöä peräkkäin, ne on käynnistettävä kaikki uudelleen PHP-päivityksen jälkeen.

## Mikä PHP-FPM on?

PHP-käsikirja kuvaa FPM:n PHP:n ensisijaiseksi FastCGI-toteutukseksi, jonka ominaisuudet ovat hyödyllisiä erityisesti raskaasti kuormitetuilla verkkosivustoilla. FPM otettiin mukaan versiossa PHP 5.3.3 omaksi SAPI:ksi eli omaksi ajotavakseen. Sen SAPI-nimi on `fpm-fcgi`.

Ero mod_php:hen: PHP ei toimi verkkopalvelimen sisällä vaan omana palvelunaan. Nginx, Apache tai jokin muu verkkopalvelin välittää PHP-pyynnöt FastCGI-protokollalla ja saa valmiin vastauksen takaisin. Verkkopalvelin ja PHP voi näin käynnistää uudelleen, konfiguroida ja suojata toisistaan riippumatta. Miten FastCGI periaatteessa toimii, kerrotaan sivulla [CGI ja FastCGI](https://phpsos.de/fi/php/cgi-und-fastcgi/).

## Master, poolit ja workerit: prosessimalli

PHP-FPM koostuu kolmesta tasosta:

1. **Master-prosessi:** lukee konfiguraation, avaa socketit ja käynnistää tai lopettaa workereita. Se ei itse suorita sovelluskoodia.
2. **Poolit:** Jokaisella poolilla on nimi, oma socket tai portti, oma Unix-käyttäjä ja omat PHP-asetukset. Käsikirja mainitsee nimenomaan eri uid:n, gid:n, chrootin, ympäristön ja php.ini-tiedoston poolia kohden.
3. **Workerit:** poolin prosesseja, jotka ottavat vastaan ja suorittavat pyyntöjä. Worker käsittelee peräkkäin monta pyyntöä, ennen kuin se korvataan.

Kuinka monta workeria on käynnissä, päättää prosessinhallinta direktiivillä `pm`:

| Tila | Käyttäytyminen | Tärkeät direktiivit |
|---|---|---|
| `static` | kiinteä määrä workereita | `pm.max_children` |
| `dynamic` | workereita ylä- ja alarajan välillä | `pm.start_servers`, `pm.min_spare_servers`, `pm.max_spare_servers` |
| `ondemand` | workerit vasta tarpeen mukaan, purku joutilaisuuden jälkeen | `pm.process_idle_timeout` (oletus 10s) |

`pm.max_children` rajoittaa kaikissa tiloissa samanaikaisten pyyntöjen määrää. `pm.max_requests` korvaa workerin tietyn pyyntömäärän jälkeen; oletus 0 tarkoittaa rajoittamatonta.

Mikä tila sopii, riippuu kuormasta. `static` pitää aina valmiina yhtä monta workeria ja sopii tasaisesti paljon käytetyille sovelluksille, kun muistia on riittävästi. `dynamic` on kompromissi useimmille verkkosivustoille. `ondemand` säästää muistia palvelimilla, joilla on paljon pieniä verkkosivustoja, koska poolit ilman kävijöitä eivät varaa workereita; vastineeksi tauon jälkeinen ensimmäinen pyyntö kestää hieman kauemmin. Liian korkea `pm.max_children` voi ajaa palvelimen muistipulaan kuormituspiikeissä, liian matala aiheuttaa odotusaikoja ja verkkopalvelimen virheilmoituksia.

## Pooli turvallisilla perusasetuksilla

Esimerkki omasta poolista kullekin verkkosivustolle, PHP-käsikirjan direktiiveillä. Polut ja arvot ovat esimerkkejä:

```ini
; /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
```

Käsikirjan mukaan `php_value`- ja `php_flag`-direktiiveillä asetettuja arvoja voi ajon aikana muuttaa `ini_set()`-funktiolla, mutta `php_admin_value`- ja `php_admin_flag`-direktiiveillä asetettuja ei. `security.limit_extensions` on oletuksena `.php .phar` ja määrittää, mitkä tiedostopäätteet FPM suorittaa pääkomentosarjana. `clear_env = yes` on oletus ja tyhjentää workerien ympäristön.

Valvontaa varten on tilasivu `pm.status_path`-asetuksen kautta ja ping-sivu `ping.path`-asetuksen kautta. Molempien tulee olla tavoitettavissa vain sisäisesti. Hitaat pyynnöt FPM kirjaa backtrace-jäljen kera, kun `request_slowlog_timeout` ja `slowlog` on asetettu.

> **Tärkeää:**
> PHP-käsikirja varoittaa: Se, joka voi avata FastCGI-yhteyden PHP-FPM:ään, hallitsee pyynnön konfiguraatiota ja voi siten suorittaa mielivaltaista koodia. PHP-FPM ei saa koskaan olla tavoitettavissa epäluotettavasta verkosta. Käyttäkää Unix-socketia tai `listen.allowed_clients`-asetusta.

## Mikä rooli PHP-FPM:llä on PHP2Shellissä?

PHP-FPM kuuluu koskeneisiin ajotapoihin. Prosessimalli tulee erityisen selvästi esiin haavoittuvuudessa CVE-2026-109619: pyyntöön kuuluva sisäinen tila voi säilyä muistin vapauttamisen jälkeen, ja myöhempi pyyntö samassa workerissa voi käyttää sitä, ennen kuin tila nollataan. Se on mahdollista vain siksi, että workerit käsittelevät monta pyyntöä peräkkäin.

Siitä seuraa kolme velvoitetta:

1. **Päivityksen asennus:** PHP 8.5.12, 8.4.27, 8.3.36 tai 8.2.35 tai jakelun vahvistettu backport.
2. **Kaikkien workerien uudelleenkäynnistys:** Levylle tulleet uudet tiedostot eivät muuta mitään, niin kauan kuin vanhat workerit ovat käynnissä. Tämä koskee jokaista asennettua FPM-versiota ja jokaista poolia. Komennot ovat sivulla [PHP-FPM ja kaikkien worker-prosessien uudelleenkäynnistys](https://phpsos.de/fi/php2shell/php-fpm-neustart/).
3. **Väliaikaisarvot lukittuina:** php.netin toimet, esimerkiksi `session.upload_progress.enabled=0`, kuuluvat `php_admin_value`- tai `php_admin_flag`-direktiivillä pooliin, eivät `.user.ini`-tiedostoon.

Poolien erottelu ei korvaa päivitystä, mutta rajoittaa vahinkoa: kun jokainen verkkosivusto toimii omalla käyttäjällään, hyökkääjä ei murron jälkeen automaattisesti pääse muiden tiedostoihin. Miltä se käytännössä näyttää, kuvaa [PHP-FPM-poolien erottaminen verkkosivustoittain](https://phpsos.de/fi/blog/php-fpm-pools-isolieren/); liittäminen Nginxiin on sivulla [Nginx ja PHP-FPM: suojaus](https://phpsos.de/fi/server/nginx-php-fpm/).

## Miten PHP SOS auttaa konkreettisesti?

- **Poolien kartoitus:** Luettelemme palvelimenne kaikki FPM-versiot, poolit, käyttäjät ja socketit.
- **Päivitys ja uudelleenkäynnistys:** Päivitämme PHP:n ja osoitamme käynnistysaikojen avulla, ettei vanhaa workeria enää ole käynnissä.
- **Poolien erottelu:** [Palvelimen koventamisen](https://phpsos.de/fi/leistungen/server-haertung/) puitteissa perustamme jokaiselle verkkosivustolle poolin, jolla on oma käyttäjä ja lukitut asetukset.
- **Tavoitettavuuden tarkistus:** Varmistamme, etteivät FastCGI-socketit ja tilasivut ole tavoitettavissa ulkopuolelta.


## Usein kysytyt kysymykset

**Mitä FPM tarkoittaa?**  
FPM tarkoittaa FastCGI Process Manageria. PHP-käsikirja kuvaa sen PHP:n ensisijaiseksi FastCGI-toteutukseksi, jonka ominaisuudet ovat hyödyllisiä erityisesti raskaasti kuormitetuilla verkkosivustoilla. Se otettiin mukaan versiossa PHP 5.3.3.

**Mikä on ero poolin ja workerin välillä?**  
Pooli on joukko worker-prosesseja, joilla on yhteinen konfiguraatio: käyttäjä, socket, rajat ja PHP-asetukset. Worker on yksittäinen prosessi, joka käsittelee pyyntöjä peräkkäin. Palvelimella voi olla monta poolia, esimerkiksi yksi jokaista verkkosivustoa kohden.

**Pitäisikö PHP-FPM:n olla tavoitettavissa TCP:n vai Unix-socketin kautta?**  
Jos verkkopalvelin toimii samalla isännällä, PHP-käsikirja suosittelee Unix-socketia. TCP:n kanssa on asetettava listen.allowed_clients, koska muuten mikä tahansa osoite saa muodostaa yhteyden. Avoimesti tavoitettavissa oleva FastCGI-portti sallii käsikirjan mukaan mielivaltaisen koodin suorittamisen.

**Suojaako pm.max_requests PHP2Shellin kaltaisilta aukoilta?**  
Ei. pm.max_requests korvaa workerin tietyn pyyntömäärän jälkeen ja auttaa lähinnä laajennusten muistivuotoja vastaan. Tulkin haavoittuvuutta vastaan auttaa vain päivitys ja sen jälkeen kaikkien worker-prosessien uudelleenkäynnistys.

## Lähteet

- [PHP-käsikirja: FastCGI Process Manager](https://www.php.net/manual/en/install.fpm.php)
- [PHP-käsikirja: FPM-konfiguraatio](https://www.php.net/manual/en/install.fpm.configuration.php)
- [php.net: PHP 5.3.3 -julkaisu](https://www.php.net/releases/5_3_3.php)
- [php.net: tietoturvatiedotteet](https://www.php.net/)
