Накратко: За да работите с PHP в контейнери, изберете подходящия вариант на официалния образ (fpm, apache или cli), активирайте php.ini за продукция, инсталирайте само нужните разширения и задайте граници за паметта и процесите, които си пасват. Контейнерите са неизменяеми: актуализация за сигурност на PHP като тази за PHP2Shell действа едва когато образът е изграден наново и всеки контейнер е рестартиран. Това ново изграждане затова принадлежи като твърд процес във всяка експлоатация на контейнери.
Защо PHP в контейнери?
Контейнерите опаковат PHP, разширенията и конфигурацията в образ, който работи еднакво на всеки сървър. За фирмите това означава: по-малко изненади между тест и продукция, по-бързо възстановяване и ясни версии. За сигурността това обаче означава и ново задължение: в контейнер никой не внедрява актуализации автоматично.
Тази страница разглежда текущата експлоатация. Как конкретно да пачнете съществуващи контейнери срещу PHP2Shell, е описано в Пачване на PHP в Docker контейнери.
Избор на правилния вариант на образа
| Вариант | Съдържание | Типично приложение |
|---|---|---|
php:<version>-fpm |
PHP-FPM, изисква предварително включен уеб сървър | продукция с Nginx, Caddy или Ingress |
php:<version>-apache |
Apache с mod_php, по подразбиране mpm_prefork | прости конструкции, по-стари приложения |
php:<version>-cli |
команден ред, единственият вариант, който съдържа и php-cgi | cron задачи, worker процеси на опашки, стъпки на изграждане |
…-alpine |
върху Alpine Linux с musl | малки образи, при някои разширения са нужни адаптации |
…-bookworm, …-trixie |
върху посочената версия на Debian | твърда основа за възпроизводими билдове |
За нови проекти по правило се препоръчва вариантът fpm с отделен контейнер за уеб сървъра. При mod_php екипът на PHP във връзка с PHP2Shell вижда най-високия риск; който използва образа apache, експлоатира точно този режим на работа.
Изграждане на образ за продукция
Компактен пример за приложение с достъп до MySQL:
FROM php:8.4-fpm-alpine
# Активиране на конфигурацията за продукция (според документацията на образа настоятелно препоръчано)
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# Само нужните разширения
RUN docker-php-ext-install -j"$(nproc)" pdo_mysql
# Собствени настройки
COPY zz-sicherheit.ini "$PHP_INI_DIR/conf.d/"
# Кодът принадлежи на root; FPM worker процесите работят като www-data и могат само да го четат
COPY . /var/www/html
Помощните скриптове на образа поемат изграждането на разширения: docker-php-ext-configure за опции, docker-php-ext-install за изграждане, docker-php-ext-enable за активиране, например след pecl install. Ако с docker-php-source се разархивира изходният код, според документацията той трябва да се изтрие отново в същия слой. Файлът zz-sicherheit.ini може да изглежда така:
expose_php = Off
display_errors = Off
log_errors = On
session.use_strict_mode = 1
session.cookie_httponly = 1
Два допълнителни принципа правят образите по-устойчиви. Първо, доставеният образ съдържа само онова, което е нужно по време на изпълнение; компилаторите, кешовете на пакети и тестовите файлове принадлежат в отделна стъпка на изграждане. Второ, потребителят, под който работи PHP, трябва да може да пише само там, където е необходимо, например в директории за качване или кеш върху прикачени томове. Много екипи допълнително работят с контейнера със защитена от запис файлова система. Внедрен PHP файл тогава много по-трудно остава трайно, а всяко рестартиране възстановява чистото състояние на образа. Това не замества изследване след инцидент, но осезаемо намалява повърхността за атака.
Процеси, памет и логове в контейнера
Три регулатора определят дали един PHP контейнер работи стабилно.
- Брой worker процеси:
pm.max_childrenв FPM пула определя колко заявки се обработват едновременно. Всеки worker може да заеме доmemory_limit. - Граница на паметта на контейнера: Тя ограничава всички процеси заедно. Като груба рецепта важи: броят на worker процесите по паметта на worker плюс резерв трябва да се побира под границата, иначе системата прекратява процеси.
- Логове: Контейнерите записват логове в стандартния изход. В PHP-FPM
catch_workers_output = yesпренасочва изхода на worker процесите към основния лог; без тази настройка според ръководството той се губи.
Полезен е и request_terminate_timeout, който прекратява отделни заявки след определен период, когато max_execution_time не действа. Как се работи с контейнери в клъстер, описва Пачване на PHP в Kubernetes.
Контейнери и сигурност: какво показа PHP2Shell
При PHP2Shell контейнерите играят двойна роля. От една страна са помощ: php.net препоръчва като временна мярка за CVE-2026-109618 memory_limit=-1 да се комбинира с граница на паметта чрез контейнер или cgroup, в идеалния случай така, че да се прекратява само засегнатият worker. RLIMIT_AS и RLIMIT_DATA според php.net са неподходящи за целта. Тази мярка не е пълна защита и не замества актуализацията.
От друга страна контейнерите са капан, ако образите не се изграждат наново. Образ с PHP 8.4.26 остава уязвим, колкото и често да се рестартира контейнерът. Едва ново изграждане на 8.4.27 или по-нова и подмяната на всички работещи контейнери затварят уязвимостта. Състоянието може да се провери директно в работещия контейнер:
docker exec <container> php -v
docker exec <container> php-fpm -v
docker exec <container> php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
Ако последната команда върне bool(false), PHP не познава директивата, въведена с коригираните версии; според ръководството версията тогава е засегната. Трайно помага само автоматично ново изграждане, както е описано в CI/CD: автоматично ново изграждане на образите на PHP.
Задайте в Dockerfile точната версия на PHP в тага и я повишавайте съзнателно. Така в кода е проследимо кога коя версия е внедрена.
Как помага PHP SOS конкретно?
В заздравяването на сървъра за PHP уеб сървъри се грижим и за контейнерите:
- Проверка на образите: Базов образ, версия на PHP, разширения и конфигурация на всеки образ.
- Заздравяване на конфигурацията: ini за продукция, компактен списък с разширения, подходящи граници на worker процесите и паметта.
- Настройване на новото изграждане: Процес, който изгражда наново и внедрява образите при нови издания на PHP.
- Контрол на средата за изпълнение: Доказваме, че във всеки работещ контейнер работи коригираната версия.
Често задавани въпроси
Кой вариант на образа на PHP е правилният?
За Nginx или друго прокси – вариантът fpm, за прост строеж с Apache – вариантът apache, за скриптове и cron задачи – вариантът cli. Вариантите с Alpine са по-малки, но се основават на musl вместо glibc, което проличава при някои разширения.
PHP в контейнер актуализира ли се автоматично?
Не. Работещият контейнер не се променя. Трябва да изградите наново образа с новата версия на PHP и да рестартирате контейнерите. Едва тогава работи коригираната версия.
Как се свързват memory_limit и границата на контейнера?
memory_limit ограничава всяка отделна PHP заявка, а границата на контейнера – целия контейнер. И двете трябва да си пасват: броят на worker процесите по паметта на worker трябва да е под границата на контейнера.
Нужен ли ми е php.ini в контейнерите?
Да. Официалните образи носят php.ini-development и php.ini-production като шаблони. За продукция документацията на образа изрично препоръчва шаблона за продукция; собствените настройки отиват в conf.d.