Laravel Production Stack
Production Laravel with Octane, Horizon, MySQL, and Redis.
Overview
Laravel is a modern PHP web framework that revolutionized web development with its elegant syntax and rich ecosystem. Built around the MVC pattern, Laravel provides powerful features like Eloquent ORM, Blade templating, and robust routing out of the box. Originally created by Taylor Otwell in 2011, Laravel has become the most popular PHP framework, powering millions of applications worldwide from startups to enterprise systems.
This production stack combines Laravel with Octane for dramatically improved performance, Horizon for queue management and monitoring, MySQL as the primary database, Redis for caching and sessions, and NGINX for high-performance web serving. Octane uses Swoole to keep Laravel applications in memory between requests, eliminating the traditional PHP bootstrap overhead and delivering response times that rival Node.js applications. Horizon provides a beautiful dashboard and code-driven configuration for Redis queues, while the entire stack is orchestrated for maximum throughput and reliability.
This configuration targets production environments where performance and scalability are critical. Enterprises running high-traffic Laravel applications, SaaS platforms with demanding performance requirements, and API-heavy applications will benefit most from this setup. The combination of Octane's memory-resident application server, Redis-backed caching and queuing, and NGINX's efficient request handling creates a Laravel deployment capable of handling thousands of concurrent requests while maintaining sub-100ms response times.
Key Features
- Laravel Octane with Swoole server for persistent application instances and sub-50ms response times
- Laravel Horizon dashboard for Redis queue monitoring, failed job management, and throughput metrics
- MySQL 8.0 with InnoDB storage engine providing ACID compliance and JSON column support
- Redis 7 Alpine for ultra-fast session storage, application caching, and queue backend
- NGINX Alpine reverse proxy with SSL termination and static asset serving
- Automated Laravel scheduler container running artisan commands every minute
- Production-optimized environment variables for database connections and cache drivers
- Isolated service networking with proper dependency management and health checks
Common Use Cases
- 1High-traffic Laravel SaaS applications requiring sub-100ms API response times
- 2E-commerce platforms with heavy database operations and real-time inventory updates
- 3Content management systems serving thousands of concurrent users
- 4API backends for mobile applications with strict performance requirements
- 5Multi-tenant Laravel applications with complex queue processing workflows
- 6Enterprise web applications requiring 99.9% uptime and horizontal scalability
- 7Laravel applications with heavy background job processing and scheduled tasks
Prerequisites
- Minimum 4GB RAM (2GB for MySQL, 1GB for Redis, 1GB for Laravel containers)
- Docker Engine 20.10+ and Docker Compose v2 for multi-container orchestration
- Generated Laravel APP_KEY and secure MySQL passwords in .env file
- SSL certificates for NGINX HTTPS configuration (Let's Encrypt recommended)
- Understanding of Laravel Octane limitations and stateful application considerations
- Experience with Laravel queue workers and Horizon configuration
For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms
docker-compose.yml
docker-compose.yml
1services: 2 mysql: 3 image: mysql:8.04 environment: 5 - MYSQL_DATABASE=laravel6 - MYSQL_USER=laravel7 - MYSQL_PASSWORD=${MYSQL_PASSWORD}8 - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}9 volumes: 10 - mysql_data:/var/lib/mysql11 networks: 12 - laravel_net1314 redis: 15 image: redis:7-alpine16 volumes: 17 - redis_data:/data18 networks: 19 - laravel_net2021 laravel: 22 build: 23 context: .24 dockerfile: Dockerfile25 command: php artisan octane:start --server=swoole --host=0.0.0.0 --port=800026 environment: 27 - APP_ENV=production28 - APP_KEY=${APP_KEY}29 - DB_CONNECTION=mysql30 - DB_HOST=mysql31 - DB_DATABASE=laravel32 - DB_USERNAME=laravel33 - DB_PASSWORD=${MYSQL_PASSWORD}34 - REDIS_HOST=redis35 - CACHE_DRIVER=redis36 - QUEUE_CONNECTION=redis37 - SESSION_DRIVER=redis38 volumes: 39 - laravel_storage:/app/storage40 depends_on: 41 - mysql42 - redis43 networks: 44 - laravel_net4546 horizon: 47 build: 48 context: .49 dockerfile: Dockerfile50 command: php artisan horizon51 environment: 52 - APP_ENV=production53 - APP_KEY=${APP_KEY}54 - DB_CONNECTION=mysql55 - DB_HOST=mysql56 - DB_DATABASE=laravel57 - DB_USERNAME=laravel58 - DB_PASSWORD=${MYSQL_PASSWORD}59 - REDIS_HOST=redis60 depends_on: 61 - mysql62 - redis63 networks: 64 - laravel_net6566 scheduler: 67 build: 68 context: .69 dockerfile: Dockerfile70 command: sh -c "while true; do php artisan schedule:run; sleep 60; done"71 environment: 72 - APP_ENV=production73 - APP_KEY=${APP_KEY}74 - DB_CONNECTION=mysql75 - DB_HOST=mysql76 - DB_DATABASE=laravel77 - DB_USERNAME=laravel78 - DB_PASSWORD=${MYSQL_PASSWORD}79 - REDIS_HOST=redis80 depends_on: 81 - mysql82 - redis83 networks: 84 - laravel_net8586 nginx: 87 image: nginx:alpine88 ports: 89 - "80:80"90 - "443:443"91 volumes: 92 - ./nginx.conf:/etc/nginx/nginx.conf:ro93 depends_on: 94 - laravel95 networks: 96 - laravel_net9798volumes: 99 mysql_data: 100 redis_data: 101 laravel_storage: 102103networks: 104 laravel_net: .env Template
.env
1# Laravel Production2MYSQL_PASSWORD=secure_mysql_password3MYSQL_ROOT_PASSWORD=secure_root_password4APP_KEY=base64:your_app_key_here56# Laravel at http://localhost7# Horizon dashboard at /horizonUsage Notes
- 1Laravel at http://localhost
- 2Horizon dashboard at /horizon
- 3Octane with Swoole for performance
- 4Run migrations before start
- 5Configure APP_KEY properly
Individual Services(6 services)
Copy individual services to mix and match with your existing compose files.
mysql
mysql:
image: mysql:8.0
environment:
- MYSQL_DATABASE=laravel
- MYSQL_USER=laravel
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
networks:
- laravel_net
redis
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
networks:
- laravel_net
laravel
laravel:
build:
context: .
dockerfile: Dockerfile
command: php artisan octane:start --server=swoole --host=0.0.0.0 --port=8000
environment:
- APP_ENV=production
- APP_KEY=${APP_KEY}
- DB_CONNECTION=mysql
- DB_HOST=mysql
- DB_DATABASE=laravel
- DB_USERNAME=laravel
- DB_PASSWORD=${MYSQL_PASSWORD}
- REDIS_HOST=redis
- CACHE_DRIVER=redis
- QUEUE_CONNECTION=redis
- SESSION_DRIVER=redis
volumes:
- laravel_storage:/app/storage
depends_on:
- mysql
- redis
networks:
- laravel_net
horizon
horizon:
build:
context: .
dockerfile: Dockerfile
command: php artisan horizon
environment:
- APP_ENV=production
- APP_KEY=${APP_KEY}
- DB_CONNECTION=mysql
- DB_HOST=mysql
- DB_DATABASE=laravel
- DB_USERNAME=laravel
- DB_PASSWORD=${MYSQL_PASSWORD}
- REDIS_HOST=redis
depends_on:
- mysql
- redis
networks:
- laravel_net
scheduler
scheduler:
build:
context: .
dockerfile: Dockerfile
command: sh -c "while true; do php artisan schedule:run; sleep 60; done"
environment:
- APP_ENV=production
- APP_KEY=${APP_KEY}
- DB_CONNECTION=mysql
- DB_HOST=mysql
- DB_DATABASE=laravel
- DB_USERNAME=laravel
- DB_PASSWORD=${MYSQL_PASSWORD}
- REDIS_HOST=redis
depends_on:
- mysql
- redis
networks:
- laravel_net
nginx
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- laravel
networks:
- laravel_net
Quick Start
terminal
1# 1. Create the compose file2cat > docker-compose.yml << 'EOF'3services:4 mysql:5 image: mysql:8.06 environment:7 - MYSQL_DATABASE=laravel8 - MYSQL_USER=laravel9 - MYSQL_PASSWORD=${MYSQL_PASSWORD}10 - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}11 volumes:12 - mysql_data:/var/lib/mysql13 networks:14 - laravel_net1516 redis:17 image: redis:7-alpine18 volumes:19 - redis_data:/data20 networks:21 - laravel_net2223 laravel:24 build:25 context: .26 dockerfile: Dockerfile27 command: php artisan octane:start --server=swoole --host=0.0.0.0 --port=800028 environment:29 - APP_ENV=production30 - APP_KEY=${APP_KEY}31 - DB_CONNECTION=mysql32 - DB_HOST=mysql33 - DB_DATABASE=laravel34 - DB_USERNAME=laravel35 - DB_PASSWORD=${MYSQL_PASSWORD}36 - REDIS_HOST=redis37 - CACHE_DRIVER=redis38 - QUEUE_CONNECTION=redis39 - SESSION_DRIVER=redis40 volumes:41 - laravel_storage:/app/storage42 depends_on:43 - mysql44 - redis45 networks:46 - laravel_net4748 horizon:49 build:50 context: .51 dockerfile: Dockerfile52 command: php artisan horizon53 environment:54 - APP_ENV=production55 - APP_KEY=${APP_KEY}56 - DB_CONNECTION=mysql57 - DB_HOST=mysql58 - DB_DATABASE=laravel59 - DB_USERNAME=laravel60 - DB_PASSWORD=${MYSQL_PASSWORD}61 - REDIS_HOST=redis62 depends_on:63 - mysql64 - redis65 networks:66 - laravel_net6768 scheduler:69 build:70 context: .71 dockerfile: Dockerfile72 command: sh -c "while true; do php artisan schedule:run; sleep 60; done"73 environment:74 - APP_ENV=production75 - APP_KEY=${APP_KEY}76 - DB_CONNECTION=mysql77 - DB_HOST=mysql78 - DB_DATABASE=laravel79 - DB_USERNAME=laravel80 - DB_PASSWORD=${MYSQL_PASSWORD}81 - REDIS_HOST=redis82 depends_on:83 - mysql84 - redis85 networks:86 - laravel_net8788 nginx:89 image: nginx:alpine90 ports:91 - "80:80"92 - "443:443"93 volumes:94 - ./nginx.conf:/etc/nginx/nginx.conf:ro95 depends_on:96 - laravel97 networks:98 - laravel_net99100volumes:101 mysql_data:102 redis_data:103 laravel_storage:104105networks:106 laravel_net:107EOF108109# 2. Create the .env file110cat > .env << 'EOF'111# Laravel Production112MYSQL_PASSWORD=secure_mysql_password113MYSQL_ROOT_PASSWORD=secure_root_password114APP_KEY=base64:your_app_key_here115116# Laravel at http://localhost117# Horizon dashboard at /horizon118EOF119120# 3. Start the services121docker compose up -d122123# 4. View logs124docker compose logs -fOne-Liner
Run this command to download and set up the recipe in one step:
terminal
1curl -fsSL https://docker.recipes/api/recipes/laravel-production/run | bashTroubleshooting
- Octane memory leaks with static variables: Restart Octane workers periodically using OCTANE_WATCH=true
- Horizon workers not processing jobs: Check Redis connection and run 'php artisan horizon:terminate' to restart
- MySQL connection refused errors: Verify MYSQL_PASSWORD environment variable matches across all Laravel services
- NGINX 502 Bad Gateway: Ensure Laravel Octane is binding to 0.0.0.0:8000, not localhost
- Laravel sessions not persisting: Confirm SESSION_DRIVER=redis and REDIS_HOST=redis in environment
- Scheduler not executing: Check that cron jobs are running every minute and APP_KEY is properly set
Community Notes
Loading...
Loading notes...
Download Recipe Kit
Get all files in a ready-to-deploy package
Includes docker-compose.yml, .env template, README, and license
Components
laraveloctanehorizonmysqlredisnginx
Tags
#laravel#php#octane#horizon#production
Category
Full Web StacksAd Space
Shortcuts: C CopyF FavoriteD Download