Setting Up an LNMP Stack with Nginx, PHP, MySQL, and phpMyAdmin Using Docker Compose

Why Use Docker Compose?

While its possible to manually run individual containers for Nginx, PHP, and MySQL, managing them becomes tedious when configuration changes are needed. Without an orchestration tool, updating a setting requires stopping the container, removing it, and running a new docker run command with the updated parameters.

Docker Compose solves this by allowing you to define your entire multi-container application in a single YAML file. With one command, you can spin up the whole stack, and when you need to change configurations, you simply edit the file and redeploy.

Installing Docker Compose

Download the binary directly from the official repository:

sudo curl -L "https://github.com/docker/compose/releases/download/v2.26.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

Apply execution permissions:

sudo chmod +x /usr/local/bin/docker-compose

Verify the installation:

docker-compose version

Preparing Host Directories

To persist data and configuration, we need to copy default configurations from temporary containers to the host machine.

Extracting PHP-FPM Assets

docker run -p 9001:9000 -d --name temp-php php:7.4-fpm
docker cp temp-php:/usr/share/nginx/html/. ./app/www
docker cp temp-php:/usr/local/etc/php/. ./config/php
docker stop temp-php && docker rm temp-php

Extracting Nginx Assets

docker run --name temp-nginx -p 8080:80 -d nginx
docker cp temp-nginx:/usr/share/nginx/html/. ./app/www
docker cp temp-nginx:/etc/nginx/conf.d/. ./config/nginx
docker cp temp-nginx:/var/log/nginx/. ./logs/nginx
docker stop temp-nginx && docker rm temp-nginx

Extracting MySQL Assets

docker run -itd --name temp-mysql -p 3307:3306 -e MYSQL_ROOT_PASSWORD=secret mysql
docker cp temp-mysql:/var/lib/mysql/. ./data/mysql
docker cp temp-mysql:/etc/mysql/. ./config/mysql
docker stop temp-mysql && docker rm temp-mysql

Extracting phpMyAdmin Assets

docker run --name temp-pma -d -e PMA_HOST=localhost phpmyadmin
docker cp temp-pma:/etc/phpmyadmin/. ./config/pma
docker stop temp-pma && docker rm temp-pma

Writing the Docker Compose File

Create a directory for the project (e.g., mkdir lnmp-stack && cd lnmp-stack) and create a file named docker-compose.yaml.

version: '3.8'

services:
  webserver:
    image: nginx:latest
    container_name: nginx-service
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./app/www:/usr/share/nginx/html
      - ./config/nginx:/etc/nginx/conf.d
      - ./logs/nginx:/var/log/nginx
    depends_on:
      - php-handler

  php-handler:
    image: php:7.4-fpm
    container_name: php-service
    restart: unless-stopped
    volumes:
      - ./app/www:/usr/share/nginx/html
      - ./config/php:/usr/local/etc/php
    environment:
      - TZ=Asia/Shanghai

  database:
    image: mysql:latest
    container_name: mysql-service
    restart: unless-stopped
    ports:
      - "3307:3306"
    environment:
      MYSQL_ROOT_PASSWORD: secret
      TZ: Asia/Shanghai
    volumes:
      - ./data/mysql:/var/lib/mysql
      - ./config/mysql:/etc/mysql/conf.d

  db-admin:
    image: phpmyadmin:latest
    container_name: pma-service
    restart: unless-stopped
    ports:
      - "8081:80"
    environment:
      PMA_HOST: database
      PMA_PORT: 3306
      PMA_ARBITRARY: 1
      TZ: Asia/Shanghai

Deployment and Management

To launch the stack in the background, run:

docker-compose up -d

If you modify the YAML file or configurations, recreate the containers:

docker-compose down
docker-compose up -d --force-recreate

Verification

Testing MySQL

Access the database container and log in:

docker exec -it mysql-service bash
mysql -u root -p

Testing phpMyAdmin

Open your browser and navigate to http://localhost:8081. Log in using the root credentials defined in the compose file.

Tags: Docker Compose LNMP nginx PHP-FPM MySQL

Posted on Sat, 06 Jun 2026 16:25:59 +0000 by R0CKY