Krótko: Aby uruchamiać PHP w kontenerach, wybierają Państwo odpowiedni wariant oficjalnego obrazu (fpm, apache lub cli), aktywują produkcyjne php.ini, instalują tylko potrzebne rozszerzenia i ustawiają limity pamięci i procesów, które do siebie pasują. Kontenery są niezmienne: aktualizacja bezpieczeństwa PHP, taka jak ta dotycząca PHP2Shell, działa dopiero wtedy, gdy obraz zostanie zbudowany od nowa, a każdy kontener zrestartowany. Ta przebudowa należy więc jako stały proces do każdej eksploatacji kontenerów.
Dlaczego PHP w kontenerach?
Kontenery pakują PHP, rozszerzenia i konfigurację w obraz, który działa tak samo na każdym serwerze. Dla firm oznacza to: mniej niespodzianek między testem a produkcją, szybsze odtwarzanie i jasne stany wersji. Dla bezpieczeństwa oznacza to jednak także nowy obowiązek: w kontenerze nikt nie instaluje aktualizacji automatycznie.
Ta strona omawia bieżącą eksploatację. Jak konkretnie załatać istniejące kontenery przeciw PHP2Shell, opisuje artykuł Poprawianie PHP w kontenerach Dockera.
Wybór właściwego wariantu obrazu
| Wariant | Zawartość | Typowe zastosowanie |
|---|---|---|
php:<version>-fpm |
PHP-FPM, wymaga serwera WWW z przodu | produkcja z Nginx, Caddy lub ingressem |
php:<version>-apache |
Apache z mod_php, domyślnie mpm_prefork | proste układy, starsze aplikacje |
php:<version>-cli |
wiersz poleceń, jako jedyny wariant zawiera też php-cgi | zadania cron, workery kolejek, kroki budowania |
…-alpine |
na Alpine Linux z musl | małe obrazy, przy niektórych rozszerzeniach potrzebne dostosowania |
…-bookworm, …-trixie |
na podanej wersji Debiana | stała baza dla powtarzalnych buildów |
Dla nowych projektów zwykle zaleca się wariant fpm z osobnym kontenerem serwera WWW. Przy mod_php zespół PHP widzi w związku z PHP2Shell najwyższe ryzyko; kto używa obrazu apache, prowadzi właśnie ten tryb pracy.
Budowanie obrazu produkcyjnego
Odchudzony przykład aplikacji z dostępem do MySQL:
FROM php:8.4-fpm-alpine
# Aktywować konfigurację produkcyjną (według dokumentacji obrazu gorąco zalecane)
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# Tylko potrzebne rozszerzenia
RUN docker-php-ext-install -j"$(nproc)" pdo_mysql
# Własne ustawienia
COPY zz-sicherheit.ini "$PHP_INI_DIR/conf.d/"
# Kod należy do roota; workery FPM działają jako www-data i mogą go tylko czytać
COPY . /var/www/html
Skrypty pomocnicze obrazu przejmują budowanie rozszerzeń: docker-php-ext-configure dla opcji, docker-php-ext-install do budowania, docker-php-ext-enable do aktywacji, na przykład po pecl install. Jeśli za pomocą docker-php-source rozpakowuje się kod źródłowy, według dokumentacji należy go usunąć w tej samej warstwie. Plik zz-sicherheit.ini mógłby wyglądać tak:
expose_php = Off
display_errors = Off
log_errors = On
session.use_strict_mode = 1
session.cookie_httponly = 1
Dwie dalsze zasady czynią obrazy odporniejszymi. Po pierwsze, dostarczany obraz zawiera tylko to, co potrzebne w czasie działania; kompilatory, pamięci podręczne pakietów i pliki testowe należą do osobnego etapu budowania. Po drugie, użytkownik, pod którym działa PHP, może zapisywać tylko tam, gdzie to konieczne, na przykład w katalogach przesyłanych plików lub cache na podłączonych woluminach. Wiele zespołów dodatkowo prowadzi kontener z systemem plików chronionym przed zapisem. Wprowadzonemu plikowi PHP jest wtedy wyraźnie trudniej pozostać na stałe, a każdy restart przywraca czysty stan obrazu. Nie zastępuje to badania po incydencie, ale wyraźnie zmniejsza powierzchnię ataku.
Procesy, pamięć i logi w kontenerze
Trzy pokrętła decydują o tym, czy kontener PHP działa stabilnie.
- Liczba workerów:
pm.max_childrenw puli FPM określa, ile żądań obsługiwanych jest jednocześnie. Każdy worker może zająć domemory_limit. - Limit pamięci kontenera: Ogranicza wszystkie procesy razem. Zgrubna reguła: liczba workerów razy pamięć na workera plus rezerwa musi mieścić się poniżej limitu, w przeciwnym razie system kończy procesy.
- Logi: Kontenery zapisują logi na standardowe wyjście. W PHP-FPM
catch_workers_output = yeskieruje wyjście workerów do logu głównego; bez tego ustawienia według podręcznika ginie ono w próżni.
Pomocne jest ponadto request_terminate_timeout, które kończy pojedyncze żądania po określonym czasie, gdy max_execution_time nie działa. Jak prowadzić kontenery w klastrze, opisuje artykuł Poprawianie PHP w Kubernetes.
Kontenery a bezpieczeństwo: czego nauczyło PHP2Shell
W PHP2Shell kontenery odgrywają podwójną rolę. Z jednej strony są pomocą: php.net zaleca jako środek przejściowy dla CVE-2026-109618 połączenie memory_limit=-1 z limitem pamięci przez kontener lub cgroup, najlepiej tak, aby kończony był tylko dotknięty worker. RLIMIT_AS i RLIMIT_DATA są do tego według php.net nieodpowiednie. Ten środek nie jest pełną ochroną i nie zastępuje aktualizacji.
Z drugiej strony kontenery są pułapką, jeśli obrazy nie są budowane od nowa. Obraz z PHP 8.4.26 pozostaje podatny, bez względu na to, jak często kontener jest restartowany. Dopiero przebudowa na 8.4.27 lub nowszą i wymiana wszystkich działających kontenerów zamykają lukę. Stan można skontrolować bezpośrednio w działającym kontenerze:
docker exec <container> php -v
docker exec <container> php-fpm -v
docker exec <container> php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
Jeśli ostatnie polecenie zwraca bool(false), PHP nie zna dyrektywy wprowadzonej w wersjach z poprawką; według podręcznika wersja jest wtedy dotknięta. Trwale pomaga tylko automatyczna przebudowa, jak opisano w artykule CI/CD: automatyczna przebudowa obrazów PHP.
Proszę ustalić w Dockerfile dokładną wersję PHP w tagu i podnosić ją świadomie. Dzięki temu w kodzie widać, kiedy jaka wersja została wdrożona.
Jak konkretnie pomaga PHP SOS?
W ramach utwardzania serwerów WWW z PHP zajmujemy się także kontenerami:
- Sprawdzenie obrazów: Obraz bazowy, wersja PHP, rozszerzenia i konfiguracja każdego obrazu.
- Utwardzenie konfiguracji: Produkcyjne ini, odchudzona lista rozszerzeń, odpowiednie limity workerów i pamięci.
- Ustawienie przebudowy: Proces, który buduje od nowa i wdraża obrazy przy nowych wydaniach PHP.
- Kontrola środowiska uruchomieniowego: Dowodzimy, że w każdym działającym kontenerze działa poprawiona wersja.
Częste pytania
Który wariant obrazu PHP jest właściwy?
Dla Nginx lub innego proxy wariant fpm, dla prostej budowy z Apache wariant apache, dla skryptów i zadań cron wariant cli. Warianty Alpine są mniejsze, ale opierają się na musl zamiast glibc, co przy niektórych rozszerzeniach bywa zauważalne.
Czy PHP w kontenerze jest aktualizowane automatycznie?
Nie. Działający kontener się nie zmienia. Trzeba zbudować obraz od nowa z nową wersją PHP i zrestartować kontenery. Dopiero wtedy działa poprawiona wersja.
Jak mają się do siebie memory_limit i limit kontenera?
memory_limit ogranicza każde pojedyncze żądanie PHP, a limit kontenera cały kontener. Oba muszą do siebie pasować: liczba workerów razy pamięć na workera powinna być poniżej limitu kontenera.
Czy w kontenerach potrzebuję php.ini?
Tak. Oficjalne obrazy dostarczają php.ini-development i php.ini-production jako szablony. Dla produkcji dokumentacja obrazu wyraźnie zaleca szablon produkcyjny; własne ustawienia trafiają do conf.d.