PHP with Composer
Best practices for Dockerfile for PHP with Composer
🐳 Annotated Dockerfile for PHP with Composer:
# Stage 1: Composer dependencies
FROM composer:lts AS composer
# Set working directory
WORKDIR /app
# Copy only the files needed for composer installation
COPY composer.json composer.lock ./
# Install dependencies with Composer
# --no-dev for production, remove for development environments
# --no-interaction for CI/CD environments
# --no-progress to reduce log output
RUN --mount=type=cache,target=/tmp/composer-cache \
composer install --no-dev --no-interaction --no-progress
# Stage 2: PHP application runtime
FROM php:8.3-fpm-alpine
# Install production dependencies and common extensions
RUN apk add --no-cache \
icu-libs \
libpq \
&& docker-php-ext-install \
pdo_mysql \
opcache
# Configure PHP for production
COPY docker/php/php.ini /usr/local/etc/php/conf.d/app.ini
COPY docker/php/fpm.conf /usr/local/etc/php-fpm.d/zz-app.conf
# Create a non-root user to run the application
RUN addgroup -g 1000 appuser && \
adduser -u 1000 -G appuser -s /bin/sh -D appuser
# Set working directory
WORKDIR /var/www/html
# Copy application files
COPY --chown=appuser:appuser . /var/www/html/
# Copy Composer dependencies from the composer stage
COPY --from=composer --chown=appuser:appuser /app/vendor/ /var/www/html/vendor/
# Set proper permissions for storage and cache directories (for Laravel projects)
RUN if [ -d "storage" ]; then \
chmod -R 775 storage bootstrap/cache; \
fi
# Switch to non-root user
USER appuser
# Expose port 9000 for PHP-FPM
EXPOSE 9000
# Set the entrypoint
CMD ["php-fpm"]
🔍 Why these are best practices:
✅ Multi-stage builds
- Separates dependency installation from the runtime environment.
- Uses official Composer image for dependency management.
- Eliminates build tools and dev dependencies from final image.
✅ Composer optimization
- Installs production dependencies only with
--no-dev
. - Uses cache mounting for faster builds.
- Copies only necessary files to optimize layer caching.
✅ Alpine-based image
- Reduces final image size dramatically (from ~1GB to ~100MB).
- Minimizes attack surface by including only necessary packages.
- Keeps application lightweight and efficient.
✅ PHP configuration optimizations
- Custom php.ini settings for production environment.
- Properly configured PHP-FPM for containerized deployments.
- Enables OPcache for better performance.
✅ Security best practices
- Runs as a non-root user to enhance container security.
- Sets proper file ownership and permissions.
- Explicitly installs only required PHP extensions.
🚀 Additional Dockerfile best practices you can adopt:
Fine-tune OPcache settings
Optimize PHP performance with production-ready OPcache settings:
# Add this to your php.ini configuration
COPY docker/php/opcache.ini /usr/local/etc/php/conf.d/opcache.ini
With opcache.ini
containing:
[opcache]
opcache.enable=1
opcache.revalidate_freq=0
opcache.validate_timestamps=0
opcache.max_accelerated_files=10000
opcache.memory_consumption=128
opcache.max_wasted_percentage=10
opcache.interned_strings_buffer=16
opcache.fast_shutdown=1
Configure for Laravel/Symfony projects
For Laravel applications, add Laravel-specific optimizations:
# In the final stage, run Laravel optimizations
RUN php artisan optimize && \
php artisan config:cache && \
php artisan route:cache && \
php artisan view:cache
For Symfony:
# Symfony optimizations
RUN APP_ENV=prod APP_DEBUG=0 php bin/console cache:warmup
Add health checks
Monitor container health:
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost:9000/ping || exit 1
Use .dockerignore
Exclude unnecessary files from your Docker build context:
.git
.github
vendor
node_modules
storage/logs/*
storage/app/*
storage/framework/cache/*
storage/framework/sessions/*
storage/framework/views/*
.env*
Dockerfile
docker-compose.yml
README.md
Environment-specific builds
Use build arguments to toggle between development and production builds:
ARG APP_ENV=production
# For development, include dev dependencies
RUN if [ "$APP_ENV" = "development" ]; then \
composer install --no-interaction; \
else \
composer install --no-dev --no-interaction --optimize-autoloader; \
fi
Add development tools conditionally
Include developer tools only in development images:
ARG APP_ENV=production
RUN if [ "$APP_ENV" = "development" ]; then \
apk add --no-cache git zip unzip && \
pecl install xdebug && \
docker-php-ext-enable xdebug; \
fi
Split web server and PHP-FPM
For production deployments, use separate containers for web server and PHP:
# Nginx configuration in a separate container
FROM nginx:alpine
COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf
COPY --from=app /var/www/html/public /var/www/html/public
EXPOSE 80
Implement proper init process
Handle signals correctly with proper init:
RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["php-fpm"]
By following these practices, you'll create Docker images for your PHP applications that are secure, efficient, and optimized for both development and production environments. These approaches help minimize build times, reduce image sizes, and provide a consistent experience across different deployment environments.
Last updated on 4/15/2025