Production-ready PHP-FPM container with Composer integration, optimized for modern PHP applications. Built on Alpine Linux with essential extensions and security hardening.
Every build ships a Sigstore-signed SBOM and a full Trivy scan — verify them yourself, no login required:
gh attestation verify oci://ghcr.io/oorabona/php:8.4-fpm-alpine --owner oorabona
Full walkthrough (SBOM payload, Trivy findings, multi-arch manifest inspection, upstream dependency tracking) → https://oorabona.github.io/docker-containers/verify-images/
# Pull from GitHub Container Registry
docker pull ghcr.io/oorabona/php:8.4-fpm-alpine
# Pull from Docker Hub
docker pull oorabona/php:8.4-fpm-alpine
entrypoint-fpm - Container initializationhealthcheck-fpm - Health monitoringcommand-loop - Background command runnercommand-loop-w-cooldown - Command runner with cooldownphp.ini settingsnobody)services:
php:
image: ghcr.io/oorabona/php:8.4-fpm-alpine
volumes:
- ./app:/var/www/app
- composer-cache:/var/www/.composer
environment:
APP_ENV: prod
APP_DEBUG: 0
networks:
- backend
healthcheck:
test: ["CMD", "healthcheck-fpm"]
interval: 30s
timeout: 10s
retries: 3
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./app:/var/www/app:ro
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- php
networks:
- backend
networks:
backend:
volumes:
composer-cache:
# Run PHP-FPM
docker run -d \
--name php-fpm \
-v $(pwd)/app:/var/www/app \
-v composer-cache:/var/www/.composer \
ghcr.io/oorabona/php:8.4-fpm-alpine
# Run Composer commands
docker run --rm \
-v $(pwd):/var/www/app \
-w /var/www/app \
ghcr.io/oorabona/php:8.4-fpm-alpine \
composer install
PHP-FPM requires a web server (Nginx, Apache, Caddy, etc.). Example Nginx configuration:
server {
listen 80;
root /var/www/app/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass php:9000; # PHP-FPM service name
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
| Argument | Description | Default |
|---|---|---|
VERSION | PHP base image version | (required) |
COMPOSER_VERSION | Composer version | 2.9.5 |
APCU_VERSION | APCu extension version | 5.1.28 |
COMPOSER_AUTH | Composer authentication JSON for private repos | "" |
| Variable | Description | Default |
|---|---|---|
APP_ENV | Application environment | prod |
APP_DEBUG | Debug mode (0=off, 1=on) | 0 |
APP_BASE_PATH | Application base path | /var/www/app/ |
COMPOSER_AUTH | Composer authentication (build-time) | "" |
COMPOSER_CACHE_DIR | Composer cache directory | /var/www/.composer/ |
| Path | Purpose |
|---|---|
/var/www/ | Application root and Composer cache |
/var/www/app/ | Application code directory |
/var/www/.composer/ | Composer cache (mount for persistence) |
/var/log/shared/ | Shared log directory |
| Port | Protocol | Purpose |
|---|---|---|
| 9000 | TCP | PHP-FPM FastCGI (NOT HTTP) |
Important: PHP-FPM listens on port 9000 for FastCGI connections. This is NOT an HTTP port. You must use a web server (Nginx, Apache, etc.) to handle HTTP requests and proxy to PHP-FPM.
nobody user--read-only flagservices:
php:
image: ghcr.io/oorabona/php:8.4-fpm-alpine
read_only: true
tmpfs:
- /tmp
- /run
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
volumes:
- ./app:/var/www/app:ro
- composer-cache:/var/www/.composer
user: "nobody:nobody"
docker run -d \
--name php-fpm \
--read-only \
--tmpfs /tmp \
--tmpfs /run \
--cap-drop ALL \
--security-opt no-new-privileges:true \
-v $(pwd)/app:/var/www/app:ro \
-v composer-cache:/var/www/.composer \
ghcr.io/oorabona/php:8.4-fpm-alpine
COMPOSER_AUTH with credentials in version control:ro)session.cookie_secure=1 works)opcache.memory_consumption=512 # 512MB cache
opcache.max_accelerated_files=20000 # Cache up to 20,000 files
opcache.validate_timestamps=0 # No revalidation (production)
opcache.revalidate_freq=2 # Check every 2 seconds (if enabled)
opcache.enable_cli=1 # Enable for CLI scripts
apc.enable_cli=1 # Enable for CLI
apc.enable=1 # Enable for web requests
memory_limit=256M # 256MB per request
max_execution_time=360 # 6 minutes
post_max_size=100M # Max POST size
upload_max_filesize=100M # Max file upload size
session.cookie_httponly=1 # JavaScript cannot access
session.cookie_secure=1 # HTTPS only
session.cookie_same_site=Strict # CSRF protection
session.use_strict_mode=1 # Reject uninitialized session IDs
This container includes pinned versions of third-party dependencies:
| Dependency | Version | Source | License |
|---|---|---|---|
| Composer | 2.9.5 | composer/composer | MIT |
| APCu | 5.1.28 | krakjoe/apcu | PHP-3.01 |
Versions are automatically monitored and updated via GitHub Actions.
Supported Platforms:
Base Images:
composer:${COMPOSER_VERSION} (Alpine)php:${VERSION} (Alpine FPM)Size: ~80MB compressed
For private repositories, pass authentication at build time:
# Create composer auth JSON
cat > auth.json <<EOF
{
"github-oauth": {
"github.com": "ghp_yourTokenHere"
}
}
EOF
# Build with authentication
docker build \
--build-arg VERSION=8.4-fpm-alpine \
--build-arg COMPOSER_AUTH="$(cat auth.json)" \
-t php:custom .
Warning: Never commit COMPOSER_AUTH to version control. Use build secrets or CI variables.
To add additional extensions, create a custom Dockerfile:
FROM ghcr.io/oorabona/php:8.4-fpm-alpine
USER root
RUN apk add --no-cache --virtual .build-deps $PHPIZE_DEPS \
&& pecl install redis \
&& docker-php-ext-enable redis \
&& apk del .build-deps
USER nobody
For development, you may want timestamps validation and display_errors:
FROM ghcr.io/oorabona/php:8.4-fpm-alpine
USER root
RUN echo "opcache.validate_timestamps=1" >> $PHP_INI_DIR/conf.d/php.ini \
&& echo "display_errors=on" >> $PHP_INI_DIR/conf.d/php.ini \
&& echo "error_reporting=E_ALL" >> $PHP_INI_DIR/conf.d/php.ini
USER nobody
ENV APP_ENV=dev
ENV APP_DEBUG=1
The container includes helper scripts for running background commands:
# Run command repeatedly
docker exec php-fpm command-loop "php artisan queue:work"
# Run with cooldown period between executions
docker exec php-fpm command-loop-w-cooldown "php artisan schedule:run"
# Check current version
./version.sh
# Check latest upstream version
./version.sh latest
# Output format (JSON for CI integration)
./version.sh --json
# From repository root
cd php
# Build with specific PHP version
docker build \
--build-arg VERSION=8.4-fpm-alpine \
--build-arg COMPOSER_VERSION=2.9.5 \
--build-arg APCU_VERSION=5.1.28 \
-t php:8.4-fpm-alpine .
# Build with docker-compose
docker-compose build
services:
php:
image: ghcr.io/oorabona/php:8.4-fpm-alpine
volumes:
- ./laravel:/var/www/app
environment:
APP_ENV: production
APP_DEBUG: 0
working_dir: /var/www/app
services:
php:
image: ghcr.io/oorabona/php:8.4-fpm-alpine
volumes:
- ./symfony:/var/www/app
environment:
APP_ENV: prod
APP_DEBUG: 0
working_dir: /var/www/app/public
For WordPress, consider using the wordpress container which includes additional optimizations.
# Check PHP-FPM status
docker exec php-fpm healthcheck-fpm
# Check PHP-FPM logs
docker logs php-fpm
# Validate FPM configuration
docker exec php-fpm php-fpm -t
# Verify PHP-FPM is listening on port 9000
docker exec php-fpm netstat -tlnp | grep 9000
# Test from web server container
docker exec nginx nc -zv php 9000
# Clear Composer cache
docker exec php-fpm composer clear-cache
# Diagnose Composer
docker exec php-fpm composer diagnose
# Check Composer version
docker exec php-fpm composer --version
# Check ownership
docker exec php-fpm ls -la /var/www/
# Fix ownership (if needed)
docker exec -u root php-fpm chown -R nobody:nobody /var/www/
Content type
Image
Digest
sha256:57c3bf373…
Size
43.8 MB
Last updated
1 day ago
docker pull oorabona/php