Ready-to-use Docker Compose stacks save hours of environment setup. This article includes tested configurations for popular web development technologies: WordPress, Node.js, and PHP. Each example can be copied and adapted for your project. To generate custom configurations, use the Docker Compose Builder on reChecker.
WordPress with MySQL
A classic stack: WordPress, MySQL 8, and phpMyAdmin. Data is persisted in volumes.
services:
wordpress:
image: wordpress:6.4-php8.2-apache
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
- wordpress_data:/var/www/html
depends_on:
- db
networks:
- wp
db:
image: mysql:8.0
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
MYSQL_ROOT_PASSWORD: rootpass
volumes:
- mysql_data:/var/lib/mysql
networks:
- wp
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 3s
retries: 5
phpmyadmin:
image: phpmyadmin:latest
ports:
- "8081:80"
environment:
PMA_HOST: db
PMA_USER: wordpress
PMA_PASSWORD: wordpress
depends_on:
db:
condition: service_healthy
networks:
- wp
volumes:
wordpress_data:
mysql_data:
networks:
wp:
driver: bridgeTo start: docker compose up -d. WordPress is available at http://localhost:8080, and phpMyAdmin at http://localhost:8081.
Local plugins and themes
Mount your plugin and theme folders for development:
wordpress:
volumes:
- wordpress_data:/var/www/html
- ./plugins:/var/www/html/wp-content/plugins/custom
- ./themes:/var/www/html/wp-content/themes/customNode.js with PostgreSQL and Redis
A stack for a modern application: Node.js, PostgreSQL, and Redis. Suitable for Express, NestJS, and Fastify.
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
NODE_ENV: development
DATABASE_URL: postgresql://app:apppass@db:5432/appdb
REDIS_URL: redis://redis:6379
volumes:
- .:/app
- /app/node_modules # исключить node_modules из sync
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- appnet
command: npm run dev
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: apppass
POSTGRES_DB: appdb
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
networks:
- appnet
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
interval: 5s
timeout: 3s
retries: 5
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- appnet
volumes:
postgres_data:
redis_data:
networks:
appnet:
driver: bridgeExample of a minimal Dockerfile for Node.js:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "start"]The volume .:/app mounts the source files for hot reload. The anonymous volume /app/node_modules prevents the host's node_modules from overwriting the container's.
PHP with MySQL and Nginx
A stack for Laravel, Symfony, or plain PHP: PHP-FPM, Nginx, and MySQL.
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- .:/var/www/html
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- php
networks:
- phpnet
php:
image: php:8.2-fpm-alpine
volumes:
- .:/var/www/html
environment:
- PHP_MEMORY_LIMIT=256M
networks:
- phpnet
depends_on:
db:
condition: service_healthy
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: appdb
MYSQL_USER: app
MYSQL_PASSWORD: apppass
volumes:
- mysql_data:/var/lib/mysql
ports:
- "3306:3306"
networks:
- phpnet
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 3s
retries: 5
volumes:
mysql_data:
networks:
phpnet:
driver: bridgeNginx configuration for PHP-FPM (nginx.conf):
server {
listen 80;
server_name localhost;
root /var/www/html/public;
index index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_hide_header X-Powered-By;
}
}For Laravel, replace root with /var/www/html/public. Install PHP extensions in the Dockerfile as needed (pdo_mysql, mbstring, opcache, etc.).
Node.js + React (Vite) with an API
Frontend and backend in one Compose file. The frontend runs in development mode with hot reload.
services:
api:
build:
context: ./api
dockerfile: Dockerfile
ports:
- "4000:4000"
environment:
NODE_ENV: development
DATABASE_URL: postgresql://app:pass@db:5432/appdb
volumes:
- ./api:/app
- /app/node_modules
depends_on:
db:
condition: service_healthy
networks:
- fullstack
frontend:
image: node:20-alpine
working_dir: /app
ports:
- "5173:5173"
volumes:
- ./frontend:/app
- /app/node_modules
command: sh -c "npm install && npm run dev -- --host"
networks:
- fullstack
environment:
- VITE_API_URL=http://localhost:4000
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: pass
POSTGRES_DB: appdb
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- fullstack
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 5s
retries: 5
volumes:
pgdata:
networks:
fullstack:
driver: bridgeProject structure:
.
├── api/
│ ├── Dockerfile
│ └── ...
├── frontend/
│ ├── package.json
│ └── ...
├── docker-compose.yml
└── nginx.confPHP with Redis for caching and queues
An extension to the PHP stack: Redis for sessions, caching, and queues (Laravel Queue, Symfony Messenger).
services:
php:
# ... как в примере выше
environment:
REDIS_HOST: redis
REDIS_PORT: 6379
SESSION_DRIVER: redis
CACHE_DRIVER: redis
QUEUE_CONNECTION: redis
depends_on:
- redis
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- phpnet
command: redis-server --appendonly yes
queue:
build:
context: .
dockerfile: Dockerfile
command: php artisan queue:work --sleep=3 --tries=3
volumes:
- .:/var/www/html
depends_on:
- php
- redis
networks:
- phpnet
volumes:
redis_data:A separate container queue processes background tasks. For Laravel Horizon, replace the command with php artisan horizon.
General recommendations
- Use health checks for databases — the application should not start until the database is ready
- Name volumes — data is preserved across restarts
- Isolate node_modules — an anonymous volume prevents conflicts with the host
- Do not commit secrets — move passwords to
.envand add it to.gitignore - Pin image versions —
postgres:16-alpineis better thanpostgres:latest
The basic concepts of Docker Compose are covered in the complete Docker Compose guide. To quickly build a configuration for your stack, use the Docker Compose Builder on reChecker.