Using Docker to Solve PHP Version Compatibility Issues: A Practical Guide
When developing modern web applications, you often face a common challenge: your application requires a specific PHP version that differs…

When developing modern web applications, you often face a common challenge: your application requires a specific PHP version that differs from what’s available on your production server. Rather than compromising your application’s requirements or risking server-wide changes, Docker offers an elegant solution.
In this guide, I’ll walk you through a real-world scenario: deploying a Laravel application that requires PHP 8.3 on a server that only has PHP 8.2 installed.
The Problem: PHP Version Mismatch
Imagine you’ve developed a new Laravel application with Filament admin panel that requires PHP 8.3, but your production server runs PHP 8.2.26 and hosts several other PHP applications that you can’t disrupt.
When attempting to install dependencies with Composer, you encounter this error:
Your lock file does not contain a compatible set of packages. Please run composer update.
Problem 1
- openspout/openspout is locked to version v4.29.1 and an update of this package was not requested.
- openspout/openspout v4.29.1 requires php ~8.3.0 || ~8.4.0 -> your php version (8.2.26) does not satisfy that requirement.
Four Potential Solutions
When facing PHP version incompatibility, you typically have four options:
- Upgrade PHP directly on the server — Risky for existing applications
- Downgrade your application’s dependencies — Not always possible or desirable
- Use separate PHP-FPM pools — Requires complex configuration
- Use Docker to isolate your application — Our recommended approach
Docker provides the perfect balance of isolation, simplicity, and maintainability. Let’s see how to implement it.
Solution: Containerizing with Docker
We’ll isolate our Laravel application in its own environment while maintaining seamless integration with the existing server infrastructure.
Step 1: Create Docker Configuration Files
First, we need to create three key configuration files:
docker-compose.yml:
services:
app:
build:
context: .
dockerfile: Dockerfile
container_name: project_app
volumes:
- ./:/var/www/html
networks:
- project_network
restart: unless-stopped
web:
image: nginx:alpine
container_name: project_web
ports:
- "8080:80"
volumes:
- ./:/var/www/html
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
networks:
- project_network
restart: unless-stopped
networks:
project_network:
driver: bridge
Dockerfile:
FROM php:8.3-fpm
# Install system dependencies
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
libzip-dev \
libicu-dev \
zip \
unzip \
nodejs \
npm
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Install PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip
RUN docker-php-ext-configure intl && docker-php-ext-install intl
# Install Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Set working directory
WORKDIR /var/www/html
docker/nginx/default.conf:
server {
listen 80;
server_name localhost;
root /var/www/html/public;
index index.php;
# Add these lines to recognize the forwarded protocol
real_ip_header X-Forwarded-For;
set_real_ip_from 172.0.0.0/8;
real_ip_recursive on;
# Trust the X-Forwarded-Proto header
map $http_x_forwarded_proto $real_scheme {
default $http_x_forwarded_proto;
'' $scheme;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass app:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# Add this line to pass the correct scheme to PHP
fastcgi_param HTTPS on;
}
}
Step 2: Modify Apache Configuration for Proxying
Since we already have Apache configured with SSL certificates, we’ll modify the VirtualHost configurations to proxy requests to our Docker container:
SSL Configuration (example.com-le-ssl.conf)
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerAdmin webmaster@localhost
ServerName example.com
ServerAlias www.example.com
# Proxy to Docker container
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
# Add these headers to inform the application it's behind HTTPS
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
</VirtualHost>
HTTP to HTTPS Redirect (example.com.conf)
<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName example.com
ServerAlias www.example.com
# We're only handling redirects here
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# Redirect all HTTP traffic to HTTPS
RewriteEngine on
RewriteCond %{SERVER_NAME} =example.com [OR]
RewriteCond %{SERVER_NAME} =www.example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
Step 3: Enable Apache Proxy Modules
sudo a2enmod proxy proxy_http headers
sudo systemctl restart apache2
Step 4: Start the Docker Environment
docker-compose up -d
Step 5: Install Dependencies and Build Assets
docker-compose exec app composer install
docker-compose exec app npm install
docker-compose exec app npm run build
Step 6: Configure Laravel for HTTPS
Update the .env
file to ensure Laravel understands it's being served over HTTPS:
APP_URL=https://www.example.com
ASSET_URL=https://www.example.com
Additionally, update the AppServiceProvider.php
to force HTTPS:
public function boot()
{
if (app()->environment('production')) {
\URL::forceScheme('https');
}
}
Step 7: Set Proper Permissions
docker-compose exec app chown -R www-data:www-data /var/www/html/storage
docker-compose exec app chmod -R 775 /var/www/html/storage
Common Challenges and Their Solutions
Throughout this process, you may encounter several challenges. Here’s how to resolve them:
1. Missing PHP Extensions
When running composer install
, you might discover missing PHP extensions. Update your Dockerfile to include the necessary extensions:
# Install system dependencies
RUN apt-get update && apt-get install -y \
libzip-dev \
libicu-dev \
# other dependencies...
# Install PHP extensions
RUN docker-php-ext-install zip
RUN docker-php-ext-configure intl && docker-php-ext-install intl
2. Database Path Issues
If your application uses SQLite, the database path in the .env
file might refer to the host path instead of the container path. Update it to:
DB_CONNECTION=sqlite
DB_DATABASE=/var/www/html/database/database.sqlite
3. Missing Frontend Assets
If the Vite manifest is missing, you need to build the frontend assets:
make npm-install
make npm-build
4. Mixed Content Warnings
If you encounter mixed content warnings because assets are being loaded over HTTP instead of HTTPS, resolve this by:
- Setting
ASSET_URL
in the.env
file - Adding
URL::forceScheme('https')
in the AppServiceProvider - Configuring Nginx to understand it’s behind an HTTPS proxy
Why This Approach Works So Well
This Docker-based solution offers several advantages:
- Perfect Isolation: Your application runs in its own environment with exactly the PHP version it needs
- Zero Impact on Existing Applications: Other applications on the server continue using the current PHP version
- Reproducible Environment: The environment is defined in code and can be recreated on any server
- Simplified Management: The Makefile makes common tasks easy to execute
- Maintained Security: SSL termination continues through Apache with existing certificates
- Flexibility: Easy to update PHP versions or add extensions without affecting the host system
Conclusion
By using Docker to isolate your Laravel application, you can successfully run applications requiring PHP 8.3 on a server with PHP 8.2, without disrupting other applications. This approach creates a separation of concerns that makes maintenance easier and reduces the risk of server-wide issues.
The combination of Docker for isolation, Apache for SSL termination, and environment-specific configuration in Laravel creates a robust, secure setup that bridges the gap between modern application requirements and existing server constraints.
For any web developer facing similar version compatibility challenges, this pattern provides a practical, reusable solution that maintains both application integrity and server stability.
Need Help With Your Laravel Project?
I specialize in building custom Laravel applications, process automation, and SaaS development. Whether you need to eliminate repetitive tasks or build something from scratch, let's discuss your project.
⚡ Currently available for 2-3 new projects

About Hafiz Riaz
Full Stack Developer from Turin, Italy. I build web applications with Laravel and Vue.js, and automate business processes. Creator of ReplyGenius, StudyLab, and other SaaS products.
View Portfolio →Related Articles

Setting Up Laravel 10 with Vue3 and Vuetify3
A complete guide to seamlessly integrating Vue3 and Vuetify3 into Laravel 10 usi...

A Beginner’s Guide to MySQL: Setting Up Your First Database and User
Navigate the essentials of MySQL with ease, and kickstart your journey in databa...

Progressive Web Apps (PWAs): The Future of Web Development
Harness the Power of PWAs to Deliver Native-Like Experiences From Your Website