Krótko: PHP-FPM (FastCGI Process Manager) uruchamia PHP jako osobną usługę obok serwera WWW. Proces master zarządza pulami, a każda pula uruchamia workery, które obsługują żądania przez FastCGI. Pule można prowadzić dla każdej strony z własnym użytkownikiem, własnymi limitami i zablokowanymi ustawieniami PHP. Ponieważ workery obsługują wiele żądań jedno po drugim, po aktualizacji PHP trzeba zrestartować je wszystkie.
Czym jest PHP-FPM?
Podręcznik PHP opisuje FPM jako podstawową implementację FastCGI w PHP z funkcjami przydatnymi głównie dla mocno obciążonych stron. FPM wprowadzono w PHP 5.3.3 jako odrębne SAPI, czyli odrębny tryb pracy. Jego nazwa SAPI brzmi fpm-fcgi.
Różnica w stosunku do mod_php: PHP nie działa w serwerze WWW, lecz jako osobna usługa. Nginx, Apache lub inny serwer WWW przekazuje żądania PHP przez protokół FastCGI i otrzymuje z powrotem gotową odpowiedź. Dzięki temu serwer WWW i PHP można restartować, konfigurować i zabezpieczać niezależnie od siebie. Jak FastCGI działa w ogólności, wyjaśniamy na stronie CGI i FastCGI.
Master, pule i workery: model procesów
PHP-FPM składa się z trzech poziomów:
- Proces master: czyta konfigurację, otwiera gniazda i uruchamia lub kończy workery. Sam nie wykonuje kodu aplikacji.
- Pule: Każda pula ma nazwę, własne gniazdo lub port, własnego użytkownika Unix i własne ustawienia PHP. Podręcznik wyraźnie wymienia różne uid, gid, chroot, środowisko i php.ini dla każdej puli.
- Workery: procesy puli, które przyjmują i wykonują żądania. Worker obsługuje kolejno wiele żądań, zanim zostanie wymieniony.
Ile workerów działa, określa menedżer procesów dyrektywą pm:
| Tryb | Zachowanie | Ważne dyrektywy |
|---|---|---|
static |
stała liczba workerów | pm.max_children |
dynamic |
workery między dolną a górną granicą | pm.start_servers, pm.min_spare_servers, pm.max_spare_servers |
ondemand |
workery dopiero w razie potrzeby, wygaszanie po bezczynności | pm.process_idle_timeout (domyślnie 10s) |
pm.max_children ogranicza we wszystkich trybach liczbę równoczesnych żądań. pm.max_requests wymienia worker po stałej liczbie żądań; domyślne 0 oznacza bez ograniczeń.
Który tryb pasuje, zależy od obciążenia. static utrzymuje zawsze tyle samo workerów i nadaje się do aplikacji równomiernie mocno używanych, mających dość pamięci operacyjnej. dynamic jest kompromisem dla większości stron. ondemand oszczędza pamięć na serwerach z wieloma małymi stronami, ponieważ pule bez odwiedzających nie zajmują workerów; w zamian pierwsze żądanie po przerwie trwa nieco dłużej. Zbyt wysoko ustawione pm.max_children może przy szczytach obciążenia doprowadzić serwer do braku pamięci, zbyt niskie prowadzi do czasów oczekiwania i komunikatów o błędach serwera WWW.
Pula z bezpiecznymi ustawieniami podstawowymi
Przykład osobnej puli dla każdej strony, z dyrektywami z podręcznika PHP. Ścieżki i wartości są przykładami:
; /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
Według podręcznika wartości ustawione przez php_value i php_flag można zmieniać w czasie działania przez ini_set(), natomiast wartości ustawione przez php_admin_value i php_admin_flag nie. security.limit_extensions jest domyślnie ustawione na .php .phar i określa, które rozszerzenia plików FPM wykonuje jako skrypt główny. clear_env = yes jest wartością domyślną i czyści środowisko workerów.
Do monitorowania służy strona statusu pod pm.status_path oraz strona ping pod ping.path. Obie powinny być dostępne tylko wewnętrznie. Wolne żądania FPM zapisuje w dzienniku z backtrace, jeśli ustawiono request_slowlog_timeout i slowlog.
Podręcznik PHP ostrzega: kto może otworzyć połączenie FastCGI z PHP-FPM, kontroluje konfigurację żądania i może przez to wykonać dowolny kod. PHP-FPM nigdy nie może być dostępny z sieci, której nie ufamy. Proszę użyć gniazda Unix lub listen.allowed_clients.
Jaką rolę PHP-FPM odgrywa w PHP2Shell?
PHP-FPM należy do dotkniętych trybów pracy. Model procesów szczególnie wyraźnie widać w CVE-2026-109619: wewnętrzny stan należący do żądania może pozostać po zwolnieniu pamięci, a późniejsze żądanie w tym samym workerze może go użyć, zanim zostanie zresetowany. Jest to możliwe tylko dlatego, że workery obsługują wiele żądań jedno po drugim.
Wynikają z tego trzy obowiązki:
- Zainstalować aktualizację: PHP 8.5.12, 8.4.27, 8.3.36 lub 8.2.35 albo potwierdzony backport dystrybucji.
- Zrestartować wszystkie workery: Nowe pliki na dysku niczego nie zmieniają, dopóki działają stare workery. Dotyczy to każdej zainstalowanej wersji FPM i każdej puli. Polecenia podajemy na stronie Restart PHP-FPM i wszystkich workerów.
- Wartości przejściowe ustawić jako zablokowane: Środki z php.net, na przykład
session.upload_progress.enabled=0, należą przezphp_admin_valuelubphp_admin_flagdo puli, a nie do.user.ini.
Rozdzielenie na pule nie zastępuje aktualizacji, ale ogranicza szkody: jeśli każda strona działa pod własnym użytkownikiem, atakujący po włamaniu nie dosięga automatycznie plików pozostałych. Jak to wygląda konkretnie, opisuje artykuł Izolowanie pul PHP-FPM dla każdej strony; włączenie do Nginx opisujemy na stronie Zabezpieczanie Nginx z PHP-FPM.
Jak konkretnie pomaga PHP SOS?
- Inwentaryzacja pul: Zestawiamy wszystkie wersje FPM, pule, użytkowników i gniazda Państwa serwera.
- Aktualizacja i restart: Aktualizujemy PHP i na podstawie czasów startu dowodzimy, że nie działa już żaden stary worker.
- Rozdzielenie pul: W ramach utwardzania serwera konfigurujemy dla każdej strony pulę z własnym użytkownikiem i zablokowanymi ustawieniami.
- Sprawdzenie dostępności: Kontrolujemy, że gniazda FastCGI i strony statusu nie są dostępne z zewnątrz.
Częste pytania
Co oznacza FPM?
FPM to skrót od FastCGI Process Manager. Podręcznik PHP opisuje go jako podstawową implementację FastCGI w PHP z funkcjami przydatnymi głównie dla mocno obciążonych stron. Wprowadzono go w PHP 5.3.3.
Jaka jest różnica między pulą a workerem?
Pula to grupa procesów workerów ze wspólną konfiguracją: użytkownikiem, gniazdem, limitami i ustawieniami PHP. Worker to pojedynczy proces, który obsługuje żądania jedno po drugim. Serwer może mieć wiele pul, na przykład po jednej dla każdej strony.
Czy PHP-FPM ma być dostępny przez TCP, czy przez gniazdo Unix?
Jeśli serwer WWW działa na tym samym hoście, podręcznik PHP zaleca gniazdo Unix. Przy TCP trzeba ustawić listen.allowed_clients, ponieważ w przeciwnym razie połączyć się może dowolny adres. Otwarcie dostępny port FastCGI pozwala według podręcznika na wykonanie dowolnego kodu.
Czy pm.max_requests chroni przed lukami takimi jak PHP2Shell?
Nie. pm.max_requests wymienia worker po stałej liczbie żądań i pomaga głównie przy wyciekach pamięci w rozszerzeniach. Przed luką w interpreterze chroni tylko aktualizacja z następującym po niej restartem wszystkich workerów.