A typical community-like PHP container image ships with ~400 packages, weighs around 500 MB, and carries dozens of known CVEs. Most of the packages (package managers, shells, libraries) have nothing to do with serving your application and are not required for it to run. They are simply dead weight that widens your attack surface
In this post, you will learn how to use Bitnami Secure Images (BSI) to build a PHP container that is a fraction of that size and starts with zero known vulnerabilities. By the end, you will have a production-ready, multi-stage Dockerfile you can drop into any Composer-based PHP project.
What Are Bitnami Secure Images (BSI)?
Bitnami Secure Images are production-ready container images built with a security-first philosophy. They give you a transparent, reliable, and auditable foundation for containerized workloads. Besides that, BSI minimal images are a special flavor of our images, thought for maximum security and performance. Some properties set BSI images apart from any typical community image:
- Minimal footprint: BSI Minimal images are built on a distroless Photon OS base: no shell, no package manager, no unnecessary libraries. The result is a dramatically smaller attack surface and a much lighter image file. This makes them an optimal choice for microservices deployment.
- Security by default: Most BSI images run their main process as an unprivileged user. This single property blocks an entire class of container-escape attacks that depend on root privileges inside the container. In addition, most BSI Minimal images are FIPS and STIG compliant, adhering to the most demanding security standards.
- Continuous patching and scanning: They are rebuilt and rescanned on a regular cadence, so new vulnerabilities are fixed as soon as the patches are released. Once a CVE is identified and remediated, a new release is typically rolled out within hours.
Beyond these runtime properties, BSI images ship with Software Bills of Materials (SBOMs) and signed attestations, giving you full visibility into your software supply chain, a critical requirement in today's compliance-driven environments.

Containerizing a PHP Application for Maximum Security
To create the most secure possible PHP application, we will use two BSI images:
-
bitnami/php-fpm - A container image packed with PHP-FPM and the most common build tools and libraries needed to develop and run most PHP applications.
-
bitnami/php-fpm-min - The minimal version of the BSI PHP-FPM image, containing only the packages and libraries strictly required to run the PHP application. This basically means maximum security and a minimum attack surface.
These images are part of the BSI trial offering so you can get their latest version from Docker Hub and try them for free. We will use a multi-stage build process to make the most of both images. The first one handles the building process (dependency installation), but only the minimal image ships to production, carrying nothing but the PHP-FPM runtime, your application code, and the vendor dependencies.
For our example, we need a Composer-based PHP application, so we'll create a minimal skeleton:
{
"name": "example/bsi-php-demo",
"description": "Minimal PHP app for BSI demo",
"require": {
"php": ">=8.4",
"monolog/monolog": "^3.0"
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
And the simplest PHP application possible as the entry point at index.php:
<?php
require __DIR__ . '/vendor/autoload.php';
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$log = new Logger('app');
$log->pushHandler(new StreamHandler('php://stdout', Logger::INFO));
$log->info('BSI PHP application is running.');
echo "Hello from a secure Bitnami container!\n";
We will create a multi-stage Dockerfile that contains the building process of our application, packed in a BSI PHP Minimal container.
FROM bitnami/php-fpm:latest AS builder
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-scripts --prefer-dist
FROM bitnami/php-fpm-min:latest AS final
WORKDIR /app
COPY --from=builder /app/vendor/ /app/vendor/
COPY composer.lock index.php ./
EXPOSE 9000
Build, Measure, and Scan
The resulting image contains only the packages and code your application needs; it is a fraction of the size of standard community images, and ships with zero known vulnerabilities.
But we don't want you to just take our word for it, go and check it yourself!
docker build -t my-secure-php-app:latest .
Check the image size:
docker images my-secure-php-app --format "{{.Repository}}:{{.Tag}}\t{{.Size}}"
You should see a size around ~133 MB — compare that to the baseline:
|
Image
|
Size
|
Packages
|
Known CVEs
|
|
php:8.4-fpm (Docker official)
|
~502 MB
|
400+
|
varies (often 30+)
|
|
bitnami/php-fpm-min
|
~133 MB
|
87
|
0 (target)
|
Now run a vulnerability scan with Trivy:
$ trivy image -q my-secure-php-app:latest
my-secure-php-app (photon 5.0)
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
Run the application
To complete our fully functional example, as PHP-FPM is a FastCGI backend, it needs a reverse proxy to serve HTTP traffic. We will choose Nginx for this purpose and take advantage of the BSI Nginx container, so we keep the same security posture across the entire stack. The simplest Nginx configuration could look like this:
server {
listen 8080;
server_name _;
location / {
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /app/index.php;
include fastcgi_params;
}
}
And finally, to put all the pieces together and run our application in our local environment, we will use Docker Compose. You have to create the following docker-compose.yml file:
services:
app:
build: .
nginx:
image: bitnami/nginx:latest
ports:
- "8080:8080"
volumes:
- ./nginx.conf:/opt/bitnami/nginx/conf/server_blocks/app.conf:ro
depends_on:
- app
Now, we are ready to run the application and access it at http://localhost:8080:
docker compose up --build

Ready for the real world
Unlike some other minimalist images, the BSI PHP minimal image includes the most popular PHP modules required for the functioning of the majority of web applications (for example, database connection modules like pdo_mysql or mysqli). This means you get a highly secure, minimalistic footprint without sacrificing the essential capabilities your application needs out of the box.
$ docker exec php-php-fpm-1 php -m
[PHP Modules]
bcmath
bz2
calendar
Core
ctype
curl
date
dom
exif
fileinfo
filter
ftp
gd
gettext
gmp
hash
iconv
intl
json
ldap
lexbor
libxml
mbstring
mysqli
mysqlnd
openssl
pcntl
pcre
PDO
pdo_mysql
pdo_sqlite
Phar
posix
random
readline
Reflection
session
SimpleXML
soap
sockets
sodium
SPL
sqlite3
standard
tokenizer
uri
xml
xmlreader
xmlwriter
xsl
Zend OPcache
zip
zlib
[Zend Modules]
Zend OPcache
Conclusion
By combining Bitnami Secure Images with a multi-stage build, you get a "security by subtraction" approach:
- ~133 MB instead of ~500 MB — roughly 4x smaller.
- Minimal attack surface - 87 packages instead of hundreds.
- Zero known CVEs in the base layer.
- SBOMs and signed attestations for full supply-chain visibility and compliance.
The result is a razor-thin container that includes only the PHP-FPM runtime, your code, and nothing else. Fewer components mean fewer potential points of failure and a significantly reduced attack surface.