Backend Development 10 min read

Setting Up a PHP Development Environment with Docker: MySQL, Nginx, and PHP‑FPM

This tutorial walks through installing Docker on macOS, configuring a fast Chinese mirror, and using Docker commands to pull, run, and link MySQL, Nginx, and PHP‑FPM containers, including volume mounting, configuration file adjustments, and installing common PHP extensions.

Laravel Tech Community
Laravel Tech Community
Laravel Tech Community
Setting Up a PHP Development Environment with Docker: MySQL, Nginx, and PHP‑FPM

Docker has become a popular technology for developers, and this guide shows how to build a complete PHP development environment using Docker Desktop for Mac, with a fast Alibaba Cloud mirror for image pulls.

Check Docker installation

docker -v

Install MySQL

Pull the latest or a specific version of MySQL:

# Pull the latest MySQL image
docker pull mysql
# Pull MySQL 5.7
docker pull mysql:5.7

Run the container with appropriate options:

# Run the latest MySQL
docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=12345678 -d mysql
# Run MySQL 5.7
docker run --name mysql_57 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=12345678 -d mysql:5.7

Key parameters:

run: create a new container

--name: container name

-p: port mapping (host:container)

-e: environment variable

-d: run in background

Enter the container:

docker exec -it mysql bash

Mount persistent data, configuration, and logs on the host to keep state after container removal:

mkdir -p docker/mysql && cd docker/mysql
mkdir data log conf

Stop and remove the previous container:

docker stop mysql && docker rm mysql

Create a custom my.cnf in docker/mysql/conf :

vim my.cnf
[mysqld]
datadir=/var/lib/mysql
default-time_zone='+8:00'
log-error=/var/log/mysql/error.log

Re‑create the MySQL container with volume mounts and restart policy:

docker run --name mysql \
  --restart=always \
  --privileged=true \
  -p 3306:3306 \
  -v $(pwd)/conf:/etc/mysql/conf.d \
  -v $(pwd)/data:/var/lib/mysql \
  -v $(pwd)/log:/var/log/mysql \
  -e MYSQL_ROOT_PASSWORD=12345678 \
  -d mysql

Access the MySQL shell inside the container and set the root password method:

$ docker exec -it mysql bash
$ mysql -u root -p
mysql> ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '12345678';
mysql> FLUSH PRIVILEGES;

Install Nginx

docker pull nginx
docker run --name nginx -p 80:80 -d nginx

Prepare host directories for configuration and logs:

mkdir -p docker/nginx && cd docker/nginx
mkdir conf log

Copy the default Nginx config to the host and mount it:

docker cp nginx:/etc/nginx/conf.d/default.conf docker/nginx/conf/default.conf

Re‑create the Nginx container with volume mounts:

docker stop nginx && docker rm nginx
docker run --name nginx -p 80:80 \
  -v $(pwd)/conf:/etc/nginx/conf.d \
  -v $(pwd)/../www:/usr/share/nginx/html \
  -v $(pwd)/log:/var/log/nginx \
  -d nginx

Install PHP‑FPM

docker pull php:fpm
docker run --name php-fpm -p 9000:9000 -d php:fpm

Create host directories for PHP configuration and logs:

mkdir -p docker/php && cd docker/php
mkdir conf log

Copy configuration files from the container:

docker cp php-fpm:/usr/local/etc/php-fpm.d/www.conf docker/php/conf/www.conf
docker cp php-fpm:/usr/local/etc/php/php.ini-production docker/php/conf/php.ini

Run PHP‑FPM linked to MySQL and with the necessary volume mounts:

docker run --name php-fpm \
  --link mysql:mysql \
  -v $(pwd)/../www:/var/www/html \
  -v $(pwd)/conf/www.conf:/usr/local/etc/php-fpm.d/www.conf \
  -v $(pwd)/conf/php.ini:/usr/local/etc/php/php.ini \
  -d php:fpm

Note: --link allows the PHP container to resolve the MySQL host as mysql .

Configure Nginx to work with PHP‑FPM

server {
    listen 80;
    server_name localhost;
    root /usr/share/nginx/html;
    charset utf-8;
    access_log /var/log/nginx/access.log main;
    error_log /var/log/nginx/error.log;
    location / {
        index index.html index.htm index.php;
        try_files $uri $uri/ /index.php?$query_string;
    }
    location ~ \.php$ {
        fastcgi_index index.php;
        fastcgi_pass php-fpm:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
    location ~ /\.ht { deny all; }
    error_page 500 502 503 504 /50x.html;
    location = /50x.html { root html; }
}

Re‑create the Nginx container with the updated configuration:

docker stop nginx && docker rm nginx
docker run --name nginx -p 80:80 \
  --link php-fpm \
  -v $(pwd)/conf:/etc/nginx/conf.d \
  -v $(pwd)/../www:/usr/share/nginx/html \
  -v $(pwd)/log:/var/log/nginx \
  -d nginx

Create a simple index.php under docker/www :

phpinfo();

Visiting http://localhost displays the PHP information page.

Install PHP extensions

docker-php-ext-install mysqli
pecl install redis && docker-php-ext-install redis
apt-get update && apt-get install -y libpng-dev libjpeg-dev libfreetype6-dev
docker-php-ext-install gd

After installing extensions, simply restart the PHP container.

Container start order: MySQL → PHP‑FPM → Nginx.

backenddevelopmentdockerMySQLPHPnginxPHP-FPM
Laravel Tech Community
Written by

Laravel Tech Community

Specializing in Laravel development, we continuously publish fresh content and grow alongside the elegant, stable Laravel framework.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.