CLOUD
Guides

Docker Compose for Production: Complete Setup Guide

CLOUD|January 21, 2026|4 min read|444 views
Docker Compose for Production: Complete Setup Guide

docker-compose.yml for Laravel + Nginx + MySQL + Redis — complete production environment. We explain the file line by line.

What is Docker Compose?

Docker Compose is a tool for defining and running multi-container applications. Instead of running each container with a separate docker run command, you write a single YAML file describing all containers, their configurations, and networks — then start everything with one command.

Why Docker Compose for production?

  • Define your entire architecture in one version-controlled file
  • Start and stop all services with a single command
  • Automatic restart on failure
  • Organized management of networks and Volumes

Structure of docker-compose.yml

version: '3.8'

services:
 # Define services here

volumes:
 # Define Volumes here

networks:
 # Define networks here

Complete Example: Laravel Application for Production

# File: docker-compose.yml
version: '3.8'

services:
 app:
 build:
 context: .
 dockerfile: Dockerfile
 container_name: laravel-app
 restart: unless-stopped
 working_dir: /var/www/app
 volumes:
 - app-storage:/var/www/app/storage
 - .env:/var/www/app/.env
 networks:
 - app-network
 depends_on:
 - db
 - redis

 nginx:
 image: nginx:alpine
 container_name: nginx
 restart: unless-stopped
 ports:
 - "80:80"
 - "443:443"
 volumes:
 - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
 - ./docker/nginx/ssl:/etc/nginx/ssl
 - app-storage:/var/www/app/storage
 networks:
 - app-network
 depends_on:
 - app

 db:
 image: mysql:8.0
 container_name: mysql
 restart: unless-stopped
 environment:
 MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
 MYSQL_DATABASE: ${DB_DATABASE}
 MYSQL_USER: ${DB_USERNAME}
 MYSQL_PASSWORD: ${DB_PASSWORD}
 volumes:
 - mysql-data:/var/lib/mysql
 - ./docker/mysql/my.cnf:/etc/mysql/conf.d/custom.cnf
 networks:
 - app-network
 ports:
 - "127.0.0.1:3306:3306"

 redis:
 image: redis:7-alpine
 container_name: redis
 restart: unless-stopped
 command: redis-server --requirepass ${REDIS_PASSWORD}
 volumes:
 - redis-data:/data
 networks:
 - app-network

 queue:
 build:
 context: .
 dockerfile: Dockerfile
 container_name: laravel-queue
 restart: unless-stopped
 command: php artisan queue:work --sleep=3 --tries=3 --max-time=3600
 volumes:
 - app-storage:/var/www/app/storage
 - .env:/var/www/app/.env
 networks:
 - app-network
 depends_on:
 - db
 - redis

 scheduler:
 build:
 context: .
 dockerfile: Dockerfile
 container_name: laravel-scheduler
 restart: unless-stopped
 command: >
 sh -c "while true; do php artisan schedule:run --verbose --no-interaction; sleep 60; done"
 volumes:
 - app-storage:/var/www/app/storage
 - .env:/var/www/app/.env
 networks:
 - app-network
 depends_on:
 - db
 - redis

volumes:
 mysql-data:
 driver: local
 redis-data:
 driver: local
 app-storage:
 driver: local

networks:
 app-network:
 driver: bridge

nginx Configuration for Production

# File: docker/nginx/default.conf
server {
 listen 80;
 server_name example.com;
 root /var/www/app/public;
 index index.php;

 client_max_body_size 100M;

 location / {
 try_files $uri $uri/ /index.php?$query_string;
 }

 location ~ \.php$ {
 fastcgi_pass app:9000;
 fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
 include fastcgi_params;
 fastcgi_buffer_size 128k;
 fastcgi_buffers 4 256k;
 }

 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
 expires 30d;
 add_header Cache-Control "public, immutable";
 }

 location ~ /\.(?!well-known) {
 deny all;
 }
}

Optimized MySQL Configuration

# File: docker/mysql/my.cnf
[mysqld]
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
max_connections = 100
slow_query_log = 1
long_query_time = 2
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

Running and Management Commands

# Start all services
docker compose up -d

# Stop all services
docker compose down

# Rebuild images
docker compose build --no-cache

# View service status
docker compose ps

# View logs
docker compose logs -f app
docker compose logs -f --tail=100

# Execute command inside a container
docker compose exec app php artisan migrate
docker compose exec app php artisan tinker
docker compose exec db mysql -u root -p

Deployment and Updates

Deployment Script

# File: deploy.sh
#!/bin/bash
set -e

echo "Pulling latest updates..."
git pull origin main

echo "Building images..."
docker compose build app

echo "Running migrations..."
docker compose exec app php artisan migrate --force

echo "Clearing cache..."
docker compose exec app php artisan optimize:clear
docker compose exec app php artisan optimize

echo "Restarting services..."
docker compose up -d --no-deps app queue scheduler

echo "Deployment completed successfully."

Zero-Downtime Update

# Build the new image
docker compose build app

# Start new container while keeping the old one
docker compose up -d --no-deps --scale app=2 app

# Wait for the new container to be ready
sleep 10

# Stop the old container
docker compose up -d --no-deps --scale app=1 app

Monitoring and Health

# Add Health Check to a container
services:
 app:
 healthcheck:
 test: ["CMD", "curl", "-f", "http://localhost:9000/health"]
 interval: 30s
 timeout: 10s
 retries: 3
 start_period: 40s

Resource Monitoring

# Resource usage per container
docker stats

# Disk usage
docker system df

Backups

# Database backup
docker compose exec db mysqldump -u root -p${DB_ROOT_PASSWORD} ${DB_DATABASE} | gzip > backup_$(date +%Y%m%d).sql.gz

# Volume backup
docker run --rm -v mysql-data:/data -v $(pwd):/backup alpine tar czf /backup/mysql-volume-backup.tar.gz /data

Running on CLOUD

CLOUD (cloud.net.sa) servers provide an ideal environment for Docker Compose in production. A VPS with 4 cores and 8GB RAM is sufficient to run a complete Laravel stack with nginx, MySQL, and Redis.

Order your cloud server from CLOUD and start deploying your application with docker compose up -d — ready in under a minute.


Get Started

Ready to build your project? Configure your cloud server with the specs your app needs, or view plans and pricing.

Share