# Izolowanie pul PHP-FPM dla każdej strony

> Izolowanie pul PHP-FPM dla każdej strony: sprawdzanie istniejących pul, ochrona gniazd, ograniczenie rozszerzeń, ukrycie stron statusu i limity dla puli.

Źródło: https://phpsos.de/pl/blog/php-fpm-pools-isolieren/  
Stan: 25.10.2026  
Dostawca: PHP SOS, Pomoc awaryjna PHP i bezpieczeństwo serwerów. Natychmiastowa pomoc przez WhatsApp: https://wa.me/491736494914?text=Dzie%C5%84%20dobry%2C%20PHP%20SOS%2C%20potrzebujemy%20pomocy%20z%20naszym%20serwerem%20PHP.%20Firma%3A%20%E2%80%A6%20Strona%20internetowa%3A%20%E2%80%A6

**Krótko:** Każda strona na serwerze powinna mieć własną pulę PHP-FPM z własnym użytkownikiem systemowym i własnym gniazdem. Rozdzielenie działa jednak dopiero ze szczegółami: uprawnienia do gniazda tylko dla serwera WWW, `security.limit_extensions` ustawione na `.php`, brak publicznie dostępnych stron statusu, własne limity procesów i czasu działania oraz oddzielne logi. Przed samym PHP2Shell chroni wyłącznie aktualizacja; pule ograniczają zasięg ataku.

## Jeden serwer, wiele stron, wspólne ryzyko

Na wielu serwerach przez lata narosło to, czego nikt tak nie planował. Strona firmowa, sklep, strona kampanii z 2019 roku i system testowy działają obok siebie, często pod tym samym użytkownikiem i w tej samej puli. Jeśli zapomniana strona kampanii zostanie przejęta, otwarte są też dane klientów sklepu.

PHP-FPM, menedżer procesów FastCGI dla PHP, rozwiązuje to za pomocą pul: grup procesów roboczych z własnymi ustawieniami. Jak działa ta podstawowa zasada, wyjaśnia artykuł [PHP-FPM wyjaśniony: menedżer procesów, pule i procesy robocze](https://phpsos.de/pl/php/php-fpm-erklaert/). Budowę oddzielnych pul z własnym użytkownikiem, własnym katalogiem tymczasowym i `open_basedir` opisuje poradnik [open_basedir i izolacja dla każdej strony](https://phpsos.de/pl/ratgeber/open-basedir/). Ten artykuł idzie o krok dalej: jak sprawdzić istniejące pule i jakie ustawienia czynią rozdzielenie wiarygodnym?

Ważne dla oceny: w PHP2Shell luki CVE-2026-109618 i CVE-2026-109619 leżą w interpreterze PHP, który współdzielą wszystkie pule danej wersji PHP. Osobna pula nie zapobiega wykorzystaniu luki. Rozstrzyga jednak, czy atakujący dotrze potem do jednej strony, czy do wszystkich.

## Pule PHP-FPM z osobnym użytkownikiem: sprawdzenie stanu

Zanim cokolwiek Państwo zmienią, proszę zyskać przegląd. Poniższe polecenia tylko odczytują. Ścieżki i numery wersji różnią się zależnie od dystrybucji:

```bash
# Wszystkie pule z użytkownikiem i gniazdem
grep -HE '^\s*(\[|user|group|listen)\s*' /etc/php/*/fpm/pool.d/*.conf

# Działające pule i ich użytkownicy
ps -eo user,pid,cmd | grep '[p]hp-fpm: pool'

# Gniazda i ich uprawnienia
ls -l /run/php/

# Sprawdzić konfigurację pod kątem błędów (niczego nie zmienia)
sudo php-fpm8.3 -t
```

Proszę zwrócić uwagę na trzy wzorce: kilka stron w tej samej puli, pule działające jako `www-data` lub nawet jako `root` oraz gniazda zapisywalne dla wszystkich użytkowników. Każdy z nich podważa rozdzielenie.

Jeśli na serwerze działa kilka wersji PHP, każda z nich ma własną usługę FPM z własnymi katalogami pul. Proszę sprawdzić wszystkie, nie tylko wersję skonfigurowaną jako ostatnia. Szczególnie stare wersje z zapomnianymi pulami są ryzykiem, ponieważ często nie są ani konserwowane, ani restartowane po aktualizacjach. Wskazówki znajdują się w artykule [Wiele wersji PHP na jednym serwerze](https://phpsos.de/pl/blog/mehrere-php-versionen-server/). Proszę zapisać wynik w małej tabeli: strona, pula, użytkownik, gniazdo, wersja PHP. Ten przegląd jest zarazem podstawą każdej późniejszej zmiany.

## Najważniejsze ustawienia dla każdej puli

Poniższy przegląd opiera się na konfiguracji FPM z podręcznika PHP. Wartości dla procesów i czasów zależą od obciążenia i aplikacji:

| Ustawienie | Cel | Zalecenie |
|---|---|---|
| `user`, `group` | użytkownik procesów roboczych | osobny użytkownik dla każdej strony, nigdy `root` |
| `listen.owner`, `listen.group`, `listen.mode` | uprawnienia do gniazda | tylko grupa serwera WWW, tryb `0660` |
| `listen.acl_users` | dostęp przez ACL zamiast właściciela | wpisać tylko użytkownika serwera WWW |
| `security.limit_extensions` | wykonywalne rozszerzenia | ograniczyć do `.php` (domyślnie `.php .phar`) |
| `clear_env` | czyszczenie zmiennych środowiskowych | pozostawić domyślne `yes` |
| `pm.max_children` | maksymalna liczba procesów roboczych | ograniczyć tak, aby jedna strona nie obciążyła całego serwera |
| `request_terminate_timeout` | przerywanie zawieszonych żądań | ustawić stosownie do najdłuższego uzasadnionego żądania |
| `pm.status_path`, `ping.path` | strona statusu i ping | ustawiać tylko w razie potrzeby i zabezpieczyć wewnętrznie |
| `slowlog`, `request_slowlog_timeout` | dziennik wolnych żądań | dla każdej puli w osobnym pliku |

Fragment utwardzonej puli wygląda tak:

```ini
; /etc/php/8.3/fpm/pool.d/shop.conf (fragment)
[shop]
user = shop
group = shop
listen = /run/php/shop.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
request_terminate_timeout = 60s

security.limit_extensions = .php
clear_env = yes

slowlog = /var/log/php/shop.slow.log
request_slowlog_timeout = 10s
php_admin_value[error_log] = /var/log/php/shop.error.log
```

Ustawienia takie jak `memory_limit` czy `session.upload_progress.enabled` ustawiają Państwo dla każdej puli za pomocą `php_admin_value` i `php_admin_flag`. Według podręcznika tych wartości nie można nadpisać przez `ini_set()`. Więcej w artykule [php_admin_value: blokowanie ustawień przed nadpisaniem](https://phpsos.de/pl/blog/php-admin-value-sperren/).

## Strony statusu i wymiana procesów roboczych: właściwa ocena

`pm.status_path` i `ping.path` są aktywne tylko wtedy, gdy zostały ustawione. Strona statusu pokazuje działające żądania, procesy i obciążenie. Dla monitoringu jest to pomocne, ale publicznie dostępna stanowi zbędne źródło informacji dla atakujących. Proszę przekazywać te ścieżki w serwerze WWW wyłącznie dla adresów wewnętrznych. Jak bezpiecznie współpracują Nginx i PHP-FPM, opisuje artykuł [Zabezpieczanie Nginx z PHP-FPM](https://phpsos.de/pl/server/nginx-php-fpm/).

`pm.max_requests` określa, po ilu żądaniach proces roboczy uruchamia się od nowa; wartość domyślna to `0`, czyli nigdy. Wartość większa od zera pomaga przy powoli rosnącym zużyciu pamięci. Jako ochrona przed PHP2Shell nie jest przeznaczona: php.net nie wymienia jej wśród środków tymczasowych i podkreśla, że w pełni chroni tylko aktualizacja. Po aktualizacji obowiązuje ponadto: wszystkie procesy robocze wszystkich pul muszą zostać zrestartowane, ponieważ w przeciwnym razie stare procesy działają dalej z podatnym kodem.

> **Wskazówka:**
> Proszę utrzymywać szablon dla nowych pul i zakładać według niego każdą nową stronę. Wtedy rozdzielenie powstaje automatycznie, zamiast być dorabiane po latach.

## Typowe błędy przy przestawianiu

Najczęstszym błędem jest nowa pula, która działa wprawdzie pod własnym użytkownikiem, ale której pliki nadal należą do `www-data`. Wtedy pula nie może zapisywać tam, gdzie powinna, a ktoś nadaje uprawnienia zbyt hojnie. Proszę wcześniej ustalić, które katalogi muszą być zapisywalne. Drugim błędem są zaplanowane zadania, które nadal działają pod starym użytkownikiem i tworzą pliki z niewłaściwym właścicielem. Trzecim jest wspólny katalog sesji dla wszystkich pul, który znosi rozdzielenie.

Po każdym przestawieniu proszę przetestować logowanie, uploady, pamięci podręczne i zaplanowane zadania strony oraz obserwować log błędów puli.

## Jak konkretnie pomaga PHP SOS?

- Inwentaryzujemy wszystkie pule, użytkowników, gniazda i ustawienia oraz pokazujemy, gdzie strony dziś współdzielą procesy lub uprawnienia.
- Konfigurujemy dla każdej strony utwardzoną pulę, z uprawnieniami do gniazda, ograniczeniem rozszerzeń, limitami zasobów i własnymi logami.
- Zabezpieczamy strony statusu, kontrolowanie restartujemy wszystkie procesy robocze i testujemy każdą stronę.
- W ramach [utwardzania serwerów](https://phpsos.de/pl/leistungen/server-haertung/) dokumentujemy rozdzielenie jako wzorzec dla przyszłych projektów.


## Częste pytania

**Dlaczego każda strona powinna mieć własną pulę PHP-FPM?**  
Osobna pula z własnym użytkownikiem systemowym rozdziela strony na poziomie procesów i uprawnień do plików. Jeśli jedna strona zostanie przejęta, kod nie może bez przeszkód czytać plików pozostałych. Ponadto limity i ustawienia można określać dla każdej strony oddzielnie.

**Czy osobna pula chroni przed PHP2Shell?**  
Nie. Luki leżą w samym interpreterze PHP, którego wszystkie pule używają wspólnie. Ochronę zapewnia tylko aktualizacja do naprawionej wersji z restartem wszystkich procesów roboczych. Oddzielne pule ograniczają jednak zasięg udanego ataku.

**Co daje security.limit_extensions?**  
Według podręcznika PHP to ustawienie ogranicza, jakie rozszerzenia plików PHP-FPM wykonuje jako skrypt główny. Domyślnie są to .php i .phar. Kto ograniczy je do .php, zapobiega wykonaniu na przykład przesłanych plików graficznych jako PHP, jeśli serwer WWW jest błędnie skonfigurowany.

**Czy strona statusu PHP-FPM jest niebezpieczna?**  
Zdradza szczegóły o działających procesach i żądaniach. Jeśli jest publicznie dostępna bez zabezpieczenia, ułatwia atakującym orientację. Według podręcznika jest aktywna tylko wtedy, gdy ustawiono pm.status_path. Wtedy serwer WWW powinien ograniczyć tę ścieżkę do adresów wewnętrznych.

## Źródła

- [Podręcznik PHP: konfiguracja FPM](https://www.php.net/manual/en/install.fpm.configuration.php)
- [Dokumentacja Nginx](https://nginx.org/en/docs/)
- [BSI (niemiecki Federalny Urząd ds. Bezpieczeństwa w Technice Informatycznej): IT-Grundschutz](https://www.bsi.bund.de/DE/Themen/Unternehmen-und-Organisationen/Standards-und-Zertifizierung/IT-Grundschutz/it-grundschutz_node.html)
