Docker for PrestaShop: Development Environment Setup
Set up Docker for PrestaShop development — multi-version testing, module workflow, database management, Xdebug debugging, and production considerations.
Why Docker for PrestaShop Development?
If you've ever tried to run PrestaShop 1.6, 1.7, 8.x, and 9.x on the same machine, you know the pain. Each version needs a different PHP version, different MySQL version, and different configuration. Installing all of that natively is a recipe for hours of troubleshooting.
Docker solves this. Each PrestaShop version runs in its own isolated container with exactly the dependencies it needs. Nothing conflicts. Nothing breaks.
- Multi-version testing: Run PS 1.7, 8.x, and 9.x simultaneously. Test a module across all of them in one afternoon.
- Isolation: Each container has its own PHP runtime, MySQL database, and file system.
- Reproducibility: Your entire environment is defined in a single
docker-compose.yml. Share it with your team and everyone gets an identical setup. - Easy cleanup: Run
docker compose down -vand everything is gone. Recreate it fresh in two minutes.
We run over 25 PrestaShop containers on a single server — from PS 1.6 through PS 9.1 — for module development and testing. Docker is the only practical way to manage that. This guide shares the patterns we've refined over years of real-world usage.
Prerequisites
Installing Docker
Ubuntu/Debian: curl -fsSL https://get.docker.com | sh — then sudo usermod -aG docker $USER to run Docker without sudo.
macOS: Download Docker Desktop for Mac (Intel and Apple Silicon supported).
Windows: Install WSL2 first, then Docker Desktop with WSL2 backend enabled.
Key Docker Concepts
- Image: A read-only template containing an OS, PHP, Apache, and PrestaShop. Official images:
prestashop/prestashopon Docker Hub. - Container: A running instance of an image. You can run multiple containers from the same image.
- Volume: Persistent storage that survives container restarts. Without volumes, data is lost when the container is removed.
- Network: A virtual network allowing containers to communicate — PrestaShop needs to reach its MySQL container.
Hardware Requirements
Budget 1.5–2GB RAM per PrestaShop instance (app + database). For 2–3 versions, 8GB RAM and an SSD is comfortable. For 10+ containers, 32GB+ and fast SSDs are recommended.
Basic Setup: Single PrestaShop Container
Create a directory and add this docker-compose.yml:
version: '3.8'
services:
prestashop:
image: prestashop/prestashop:8.2
container_name: my-ps-shop
ports:
- "8080:80"
environment:
- DB_SERVER=db
- DB_USER=prestashop
- DB_PASSWD=prestashop_password
- DB_NAME=prestashop
- PS_DOMAIN=localhost:8080
- PS_FOLDER_ADMIN=admin-dev
- PS_FOLDER_INSTALL=disabled
- ADMIN_MAIL=admin@yourshop.com
- ADMIN_PASSWD=admin_password_123
volumes:
- ps-data:/var/www/html
depends_on:
- db
db:
image: mysql:8.0
container_name: my-ps-shop-db
environment:
- MYSQL_ROOT_PASSWORD=root_password
- MYSQL_DATABASE=prestashop
- MYSQL_USER=prestashop
- MYSQL_PASSWORD=prestashop_password
volumes:
- db-data:/var/lib/mysql
volumes:
ps-data:
db-data:
DB_SERVER must match the service name (db). PS_DOMAIN tells PrestaShop where it's accessible. PS_FOLDER_INSTALL=disabled skips the install wizard on subsequent starts. Start with docker compose up -d and watch the first-time install with docker compose logs -f prestashop (takes 1-2 minutes).
Access your store at http://localhost:8080 and the back office at http://localhost:8080/admin-dev.
Always use named volumes for your database. Without volumes, removing a container destroys all data — products, orders, everything. Named volumes persist until you explicitly delete them.
Multi-Version Testing Setup
This is where Docker shines. Running three PrestaShop versions side by side is just a matter of defining them in your compose file with different ports:
version: '3.8'
services:
ps178:
image: prestashop/prestashop:1.7.8
ports: ["8081:80"]
environment:
- DB_SERVER=ps178-db
- PS_DOMAIN=localhost:8081
# ... same pattern as above
volumes:
- ps178-data:/var/www/html
networks: [ps-network]
ps178-db:
image: mysql:5.7
volumes: [ps178-db-data:/var/lib/mysql]
networks: [ps-network]
ps82:
image: prestashop/prestashop:8.2
ports: ["8082:80"]
environment:
- DB_SERVER=ps82-db
- PS_DOMAIN=localhost:8082
volumes:
- ps82-data:/var/www/html
networks: [ps-network]
ps82-db:
image: mysql:8.0
command: --default-authentication-plugin=mysql_native_password
volumes: [ps82-db-data:/var/lib/mysql]
networks: [ps-network]
ps9:
image: prestashop/prestashop:9.0
ports: ["8083:80"]
environment:
- DB_SERVER=ps9-db
- PS_DOMAIN=localhost:8083
volumes:
- ps9-data:/var/www/html
networks: [ps-network]
ps9-db:
image: mysql:8.0
command: --default-authentication-plugin=mysql_native_password
volumes: [ps9-db-data:/var/lib/mysql]
networks: [ps-network]
networks:
ps-network:
driver: bridge
Pick a consistent port scheme: 8081 for PS 1.7, 8082 for PS 8.x, 8083 for PS 9.x. For a nicer experience, use Nginx Proxy Manager to assign hostnames like ps178.dev.local instead of port numbers.
Always use separate databases. Never share a single MySQL instance across PrestaShop versions — the schema differs between versions, and migrations will corrupt data.
Module Development Workflow
Bind-mount your module directory into the container so every edit is immediately available:
volumes:
- ps82-data:/var/www/html
- /home/user/modules/my_module:/var/www/html/modules/my_module
To test across all versions, mount the same directory into every container. Edit one file, refresh three browser tabs — your change is live everywhere.
Symlinks vs Volume Mounts
Volume mounts (recommended): Changes are instant, works across all platforms, clean separation. Symlinks: Only works if PrestaShop files are on the host filesystem, doesn't work well with Docker volumes. For most setups, volume mounts are the right choice.
Handling the Cache
PrestaShop aggressively caches templates and configs. During development, clear cache after changes:
docker exec ps82 rm -rf /var/www/html/var/cache/*
Or disable template cache in Back Office > Advanced Parameters > Performance during active development. Re-enable it when testing is complete — cache-related bugs are real.
Database Management
Connecting to MySQL
# Interactive MySQL session
docker exec -it ps82-db mysql -u root -p'root' prestashop
# Run a single query
docker exec ps82-db mysql -u root -p'root' -e "SELECT COUNT(*) FROM ps_product;" prestashop
phpMyAdmin Container
phpmyadmin:
image: phpmyadmin:latest
ports: ["9090:80"]
environment:
- PMA_HOSTS=ps178-db,ps82-db,ps9-db
- PMA_USER=root
- PMA_PASSWORD=root
networks: [ps-network]
Import and Export
# Export
docker exec ps82-db mysqldump -u root -p'root' prestashop > backup.sql
# Import
docker exec -i ps82-db mysql -u root -p'root' prestashop < backup.sql
Persistent vs Ephemeral
Persistent (named volumes): Data survives restarts — use for main development environments. Ephemeral (no volume): Fresh install every time — useful for "does this module install cleanly on a blank store?" tests.
Email Testing with Mailpit
Mailpit catches all outgoing emails and displays them in a web UI — essential for testing checkout flows without sending real emails.
mailpit:
image: axllent/mailpit
ports:
- "8025:8025" # Web UI
- "1025:1025" # SMTP
networks: [ps-network]
In PrestaShop Back Office > Advanced Parameters > E-mail: set SMTP server to mailpit, port 1025, no encryption, no authentication. View caught emails at http://localhost:8025.
Debugging with Xdebug
Xdebug 3 Configuration
Create a custom Dockerfile:
FROM prestashop/prestashop:8.2
RUN pecl install xdebug && docker-php-ext-enable xdebug
COPY xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
The xdebug.ini:
[xdebug]
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.idekey=VSCODE
On Linux, add extra_hosts: ["host.docker.internal:host-gateway"] to your compose service — host.docker.internal doesn't exist by default on Linux.
VS Code Setup
Install the PHP Debug extension and add to .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [{
"name": "Listen for Xdebug (Docker)",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html/modules/my_module": "${workspaceFolder}"
}
}]
}
The pathMappings are critical — they tell VS Code how container paths map to local paths. Without this, breakpoints won't trigger.
PHPStorm
Settings > PHP > Servers: add a server with localhost and your container's port, mapping /var/www/html to your local project. Set Xdebug port to 9003 under PHP > Debug and click "Start Listening."
Useful Docker Commands
| Task | Command |
|---|---|
| Start all containers | docker compose up -d |
| Stop all containers | docker compose down |
| Stop and delete all data | docker compose down -v |
| View logs | docker compose logs -f |
| Clear PS cache | docker exec CONTAINER rm -rf /var/www/html/var/cache/* |
| MySQL CLI | docker exec -it CONTAINER-db mysql -u root -p'PASS' prestashop |
| Export database | docker exec CONTAINER-db mysqldump -u root -p'PASS' prestashop > backup.sql |
| Import database | docker exec -i CONTAINER-db mysql -u root -p'PASS' prestashop < backup.sql |
| Shell into container | docker exec -it CONTAINER bash |
| Check resource usage | docker stats --no-stream |
| Rebuild after Dockerfile changes | docker compose up -d --build |
| Run PrestaShop console | docker exec CONTAINER php bin/console cache:clear --env=prod |
| Run Composer in module | docker exec -w /var/www/html/modules/my_module CONTAINER composer install |
Production Considerations
For most PrestaShop shops, Docker is a development tool. Production stores run better on traditional hosting because:
- A single-server LAMP stack is simpler to maintain and monitor
- Native file I/O is faster than Docker volumes (PrestaShop loads thousands of PHP files per request)
- Most PrestaShop hosts provide cPanel/Plesk, not Docker
Docker in production makes sense when: you have a large dev team with CI/CD pipelines, you need auto-scaling during sales events, you manage 10+ stores, or you need zero-downtime deployments (build new image, swap in, roll back if broken).
Docker Compose vs Kubernetes: Compose handles up to 20–30 containers on one server and is simple to manage. Kubernetes adds auto-scaling, self-healing, and multi-node orchestration but requires significant infrastructure. For most PrestaShop deployments, Compose on a powerful server is sufficient.
Common Problems and Solutions
File Permission Issues
Symptom: "Permission denied" errors, can't upload modules or save images.
Cause: Apache runs as www-data (UID 33) inside the container, but mounted host files may be owned by your user (UID 1000).
docker exec my-ps-shop chown -R www-data:www-data /var/www/html/var
docker exec my-ps-shop chown -R www-data:www-data /var/www/html/img
docker exec my-ps-shop chown -R www-data:www-data /var/www/html/modules
Container Can't Connect to Database
DB_SERVERmust match the MySQL service name in your compose file exactly- MySQL may not be ready — add a healthcheck and use
depends_on: condition: service_healthy - Both containers must be on the same Docker network
- MySQL 8.0 uses
caching_sha2_passwordby default — addcommand: --default-authentication-plugin=mysql_native_passwordto the MySQL service
Slow File I/O on macOS
Symptom: Pages take 10–30 seconds to load with bind mounts.
Solutions:
- VirtioFS: Switch from gRPC FUSE to VirtioFS in Docker Desktop settings — biggest single improvement
- Mount less: Only mount your module directory, use named volumes for PrestaShop core
- Mutagen: Fast two-way file sync that eliminates the macOS penalty
SSL in Development
Payment modules and social login often require HTTPS. Options:
- Nginx Proxy Manager: Handles SSL termination for all containers. Cleanest approach.
- mkcert: Generate locally-trusted certificates with
mkcert localhostand mount them into Apache. - Traefik: Auto-discovers containers and provisions certificates.
Container Runs Out of Memory
MySQL 8.0 is memory-hungry by default. Limit it:
command: >
--innodb-buffer-pool-size=128M
--max-connections=50
On Docker Desktop (macOS/Windows), increase the global memory limit in Settings > Resources to at least 6GB for 3+ containers. Stop containers you're not actively using: docker compose stop ps178.
Auto-Install Loops
If PrestaShop reinstalls on every restart, ensure your /var/www/html volume persists and PS_FOLDER_INSTALL=disabled is set in your environment.
Mixed Content After Port Change
Update the domain in the database when you change port mappings:
docker exec ps82-db mysql -u root -p'root' -e "
UPDATE ps_configuration SET value='localhost:8082'
WHERE name IN ('PS_SHOP_DOMAIN','PS_SHOP_DOMAIN_SSL');
UPDATE ps_shop_url SET domain='localhost:8082', domain_ssl='localhost:8082';
" prestashop
Summary
Docker transforms PrestaShop development from a fragile, single-version experience into a reproducible, multi-version workflow. The initial setup takes an afternoon. After that, you can spin up any PrestaShop version in minutes, test modules across all supported versions simultaneously, and share your exact environment with your team.
Start with the basic single-container setup. Once comfortable, add more versions, phpMyAdmin, Mailpit, and Xdebug. The compose files in this guide are production-tested patterns from our own infrastructure. Copy them, adapt them, and build on them.
The PrestaShop Docker repository on GitHub is an excellent resource for staying current with official image updates and best practices.
More guides available
Browse our knowledge base for more practical PrestaShop tutorials, or reach out if you need help.