docker.recipes

LEMP Stack

beginner

Classic Linux, NGINX, MySQL, PHP stack for hosting PHP applications.

Overview

NGINX is a high-performance web server and reverse proxy server that has become the backbone of modern web infrastructure, powering over 400 million websites worldwide. Originally developed by Igor Sysoev to solve the C10K problem (handling 10,000 concurrent connections), NGINX uses an event-driven, asynchronous architecture that dramatically outperforms traditional process-based servers under high load conditions. Its lightweight footprint and efficient resource utilization make it ideal for serving static content, handling SSL termination, and proxying requests to backend applications. The LEMP stack combines NGINX's superior performance characteristics with MySQL's proven relational database capabilities and PHP-FPM's optimized process management for PHP applications. This configuration creates a highly efficient web application platform where NGINX handles incoming HTTP requests and serves static files directly, while forwarding PHP requests to the PHP-FPM process manager through FastCGI protocol. MySQL provides robust ACID-compliant data storage with InnoDB's advanced transaction support, making this stack particularly effective for database-driven web applications that require both speed and reliability. This stack is ideal for developers migrating from traditional LAMP setups who need better performance, system administrators managing high-traffic PHP applications, and businesses running content management systems like WordPress or Drupal in production environments. The combination offers significant advantages over Apache-based stacks, including lower memory consumption, better concurrent connection handling, and superior static file serving performance, while maintaining full compatibility with existing PHP applications.

Key Features

  • Event-driven, asynchronous NGINX architecture for handling thousands of concurrent connections with minimal memory usage
  • PHP-FPM process manager with adaptive process spawning and built-in opcode caching support
  • MySQL InnoDB storage engine with ACID compliance and row-level locking for high-concurrency applications
  • FastCGI protocol integration between NGINX and PHP-FPM for efficient request processing
  • NGINX reverse proxy capabilities with built-in load balancing algorithms and health checks
  • MySQL Query Cache and full-text search capabilities for optimized database performance
  • HTTP/2 support in NGINX for improved page load times and resource multiplexing
  • PHP 8.3 JIT compilation and improved type system for enhanced application performance

Common Use Cases

  • 1High-traffic WordPress or Drupal websites requiring better performance than traditional Apache setups
  • 2E-commerce platforms built with PHP frameworks like Laravel, Symfony, or CodeIgniter
  • 3Content management systems serving static assets and dynamic PHP content simultaneously
  • 4Development environments for PHP applications that mirror production LEMP deployments
  • 5Multi-tenant SaaS applications requiring efficient resource utilization and database isolation
  • 6API backends for mobile applications using PHP frameworks with MySQL data persistence
  • 7Legacy LAMP stack migrations seeking improved performance without application code changes

Prerequisites

  • Minimum 1.5GB RAM available (256MB for NGINX, 512MB for PHP-FPM, 1GB for MySQL)
  • Docker Engine 20.10+ and Docker Compose V2 for proper networking and volume support
  • Port 80 available on host system for NGINX web server access
  • Basic understanding of PHP-FPM configuration and FastCGI protocol for optimization
  • Familiarity with NGINX server blocks and location directives for custom routing
  • Knowledge of MySQL user management and database security practices

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 nginx:
3 image: nginx:alpine
4 container_name: nginx
5 restart: unless-stopped
6 volumes:
7 - ./src:/var/www/html
8 - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
9 ports:
10 - "80:80"
11 depends_on:
12 - php
13 networks:
14 - lemp
15
16 php:
17 image: php:8.3-fpm-alpine
18 container_name: php
19 restart: unless-stopped
20 volumes:
21 - ./src:/var/www/html
22 networks:
23 - lemp
24
25 mysql:
26 image: mysql:8.0
27 container_name: mysql
28 restart: unless-stopped
29 environment:
30 MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
31 MYSQL_DATABASE: ${MYSQL_DATABASE}
32 MYSQL_USER: ${MYSQL_USER}
33 MYSQL_PASSWORD: ${MYSQL_PASSWORD}
34 volumes:
35 - mysql_data:/var/lib/mysql
36 networks:
37 - lemp
38
39volumes:
40 mysql_data:
41
42networks:
43 lemp:
44 driver: bridge

.env Template

.env
1# MySQL Configuration
2MYSQL_ROOT_PASSWORD=rootpassword
3MYSQL_DATABASE=myapp
4MYSQL_USER=appuser
5MYSQL_PASSWORD=changeme

Usage Notes

  1. 1Place PHP files in ./src directory
  2. 2Create nginx/default.conf with PHP-FPM config (fastcgi_pass php:9000)
  3. 3Access at http://localhost
  4. 4PHP connects to MySQL: host=mysql, port=3306
  5. 5Install PHP extensions: docker-compose exec php docker-php-ext-install pdo_mysql
  6. 6Classic LAMP alternative using NGINX instead of Apache

Individual Services(3 services)

Copy individual services to mix and match with your existing compose files.

nginx
nginx:
  image: nginx:alpine
  container_name: nginx
  restart: unless-stopped
  volumes:
    - ./src:/var/www/html
    - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
  ports:
    - "80:80"
  depends_on:
    - php
  networks:
    - lemp
php
php:
  image: php:8.3-fpm-alpine
  container_name: php
  restart: unless-stopped
  volumes:
    - ./src:/var/www/html
  networks:
    - lemp
mysql
mysql:
  image: mysql:8.0
  container_name: mysql
  restart: unless-stopped
  environment:
    MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    MYSQL_DATABASE: ${MYSQL_DATABASE}
    MYSQL_USER: ${MYSQL_USER}
    MYSQL_PASSWORD: ${MYSQL_PASSWORD}
  volumes:
    - mysql_data:/var/lib/mysql
  networks:
    - lemp

Quick Start

terminal
1# 1. Create the compose file
2cat > docker-compose.yml << 'EOF'
3services:
4 nginx:
5 image: nginx:alpine
6 container_name: nginx
7 restart: unless-stopped
8 volumes:
9 - ./src:/var/www/html
10 - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
11 ports:
12 - "80:80"
13 depends_on:
14 - php
15 networks:
16 - lemp
17
18 php:
19 image: php:8.3-fpm-alpine
20 container_name: php
21 restart: unless-stopped
22 volumes:
23 - ./src:/var/www/html
24 networks:
25 - lemp
26
27 mysql:
28 image: mysql:8.0
29 container_name: mysql
30 restart: unless-stopped
31 environment:
32 MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
33 MYSQL_DATABASE: ${MYSQL_DATABASE}
34 MYSQL_USER: ${MYSQL_USER}
35 MYSQL_PASSWORD: ${MYSQL_PASSWORD}
36 volumes:
37 - mysql_data:/var/lib/mysql
38 networks:
39 - lemp
40
41volumes:
42 mysql_data:
43
44networks:
45 lemp:
46 driver: bridge
47EOF
48
49# 2. Create the .env file
50cat > .env << 'EOF'
51# MySQL Configuration
52MYSQL_ROOT_PASSWORD=rootpassword
53MYSQL_DATABASE=myapp
54MYSQL_USER=appuser
55MYSQL_PASSWORD=changeme
56EOF
57
58# 3. Start the services
59docker compose up -d
60
61# 4. View logs
62docker compose logs -f

One-Liner

Run this command to download and set up the recipe in one step:

terminal
1curl -fsSL https://docker.recipes/api/recipes/lemp-stack/run | bash

Troubleshooting

  • 502 Bad Gateway errors: Ensure PHP-FPM container is running and NGINX default.conf has correct fastcgi_pass php:9000 directive
  • PHP extensions missing (like pdo_mysql): Run docker-compose exec php docker-php-ext-install pdo_mysql mysqli to install database connectors
  • File permission errors in PHP: Check that ./src directory has proper ownership and PHP-FPM can read/write files with correct user mapping
  • MySQL connection refused from PHP: Verify database host is set to 'mysql' (container name) not 'localhost' in PHP database configuration
  • NGINX fails to start with port binding error: Ensure no other web server is using port 80 or modify port mapping in docker-compose.yml
  • Slow MySQL queries on first startup: Allow time for MySQL 8.0 initialization and consider using mysql:8.0 specific configuration optimizations

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

Ad Space