# Експлоатация на PHP в контейнери

> PHP в контейнер: варианти на образите, php.ini за продукция, разширения, граници на паметта, логове и актуализации. С примери и връзка с PHP2Shell.

Източник: https://phpsos.de/bg/php/php-in-containern/  
Актуалност: 25.10.2026  
Доставчик: PHP SOS, Спешна помощ за PHP и сигурност на сървъри. Незабавна помощ по WhatsApp: https://wa.me/491736494914?text=%D0%97%D0%B4%D1%80%D0%B0%D0%B2%D0%B5%D0%B9%D1%82%D0%B5%2C%20PHP%20SOS%2C%20%D0%B8%D0%BC%D0%B0%D0%BC%D0%B5%20%D0%BD%D1%83%D0%B6%D0%B4%D0%B0%20%D0%BE%D1%82%20%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%20%D1%81%20%D0%BD%D0%B0%D1%88%D0%B8%D1%8F%20PHP%20%D1%81%D1%8A%D1%80%D0%B2%D1%8A%D1%80.%20%D0%A4%D0%B8%D1%80%D0%BC%D0%B0%3A%20%E2%80%A6%20%D0%A3%D0%B5%D0%B1%D1%81%D0%B0%D0%B9%D1%82%3A%20%E2%80%A6

**Накратко:** За да работите с PHP в контейнери, изберете подходящия вариант на официалния образ (`fpm`, `apache` или `cli`), активирайте php.ini за продукция, инсталирайте само нужните разширения и задайте граници за паметта и процесите, които си пасват. Контейнерите са неизменяеми: актуализация за сигурност на PHP като тази за PHP2Shell действа едва когато образът е изграден наново и всеки контейнер е рестартиран. Това ново изграждане затова принадлежи като твърд процес във всяка експлоатация на контейнери.

## Защо PHP в контейнери?

Контейнерите опаковат PHP, разширенията и конфигурацията в образ, който работи еднакво на всеки сървър. За фирмите това означава: по-малко изненади между тест и продукция, по-бързо възстановяване и ясни версии. За сигурността това обаче означава и ново задължение: в контейнер никой не внедрява актуализации автоматично.

Тази страница разглежда текущата експлоатация. Как конкретно да пачнете съществуващи контейнери срещу PHP2Shell, е описано в [Пачване на PHP в Docker контейнери](https://phpsos.de/bg/php2shell/docker-container-patchen/).

## Избор на правилния вариант на образа

| Вариант | Съдържание | Типично приложение |
|---|---|---|
| `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:

```dockerfile
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` може да изглежда така:

```ini
expose_php = Off
display_errors = Off
log_errors = On
session.use_strict_mode = 1
session.cookie_httponly = 1
```

Два допълнителни принципа правят образите по-устойчиви. Първо, доставеният образ съдържа само онова, което е нужно по време на изпълнение; компилаторите, кешовете на пакети и тестовите файлове принадлежат в отделна стъпка на изграждане. Второ, потребителят, под който работи PHP, трябва да може да пише само там, където е необходимо, например в директории за качване или кеш върху прикачени томове. Много екипи допълнително работят с контейнера със защитена от запис файлова система. Внедрен PHP файл тогава много по-трудно остава трайно, а всяко рестартиране възстановява чистото състояние на образа. Това не замества изследване след инцидент, но осезаемо намалява повърхността за атака.

## Процеси, памет и логове в контейнера

Три регулатора определят дали един PHP контейнер работи стабилно.

1. **Брой worker процеси:** `pm.max_children` в FPM пула определя колко заявки се обработват едновременно. Всеки worker може да заеме до `memory_limit`.
2. **Граница на паметта на контейнера:** Тя ограничава всички процеси заедно. Като груба рецепта важи: броят на worker процесите по паметта на worker плюс резерв трябва да се побира под границата, иначе системата прекратява процеси.
3. **Логове:** Контейнерите записват логове в стандартния изход. В PHP-FPM `catch_workers_output = yes` пренасочва изхода на worker процесите към основния лог; без тази настройка според ръководството той се губи.

Полезен е и `request_terminate_timeout`, който прекратява отделни заявки след определен период, когато `max_execution_time` не действа. Как се работи с контейнери в клъстер, описва [Пачване на PHP в Kubernetes](https://phpsos.de/bg/server/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 или по-нова и подмяната на всички работещи контейнери затварят уязвимостта. Състоянието може да се провери директно в работещия контейнер:

```bash
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](https://phpsos.de/bg/blog/php-images-in-ci-neu-bauen/).

> **Съвет:**
> Задайте в Dockerfile точната версия на PHP в тага и я повишавайте съзнателно. Така в кода е проследимо кога коя версия е внедрена.

## Как помага PHP SOS конкретно?

В [заздравяването на сървъра за PHP уеб сървъри](https://phpsos.de/bg/leistungen/server-haertung/) се грижим и за контейнерите:

- **Проверка на образите:** Базов образ, версия на 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.

## Източници

- [Docker Official Image: PHP](https://hub.docker.com/_/php)
- [Ръководство на PHP: Конфигурация на FPM](https://www.php.net/manual/en/install.fpm.configuration.php)
- [php.net: Съобщение за сигурност от 21.10.2026 г.](https://www.php.net/)
