How to Deploy PHP FPM, NGINX, and MySQL with Docker Compose

Posted October 22, 2023
How to Deploy PHP FPM, NGINX, and MySQL with Docker Compose

Setting up a PHP local development environment using PHP FPM, NGINX, and MySQL is complex. Yet, leveraging the prowess of Docker and Docker Compose, this process is easier and flawless. In this comprehensive guide, we’ll go through the step-by-step process of deploying PHP FPM, NGINX, and MySQL with Docker Compose all in one container.

You will learn:

  • How to run PHP apps using FPM (FastCGI Process Manager) alongside Docker Compose.
  • The right way to set an NGINX server with a Docker container to run PHP FPM code.
  • To make this setup deeper, you will learn how to combine MySQL database and PHPMyAdmin to run PHP FPM code alongside NGINX with Docker Compose.

Let’s Dive into this comprehensive guide and learn How to Deploy PHP FPM, NGINX, and MySQL with Docker Compose.

Prerequisites

Creating a PHP FPM app container with Docker Compose NGINX and MySQL is a step-by-step process. Before diving in, ensure:

nginx-php-app/
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ nginx/
β”‚ β”‚ β”œβ”€β”€ nginx.conf
β”‚ β”‚ └── Dockerfile
└── app/
    └── index.php

How to Deploy PHP FPM, NGINX, and MySQL with Docker Compose

This will represent the following:

  • Dockerfile contains configurations to set up PHP with FPM on Docker and install necessary PHP extensions.
  • docker-compose.yml creates services to run PHP FPM, NGINX, and other services like a database or cache.
  • nginx/nginx.conf is the NGINX main configuration file and your application-specific NGINX settings.
  • nginx/Dockerfile will show you the Docker configurations needed to package the NGINX server. app/index.php contains the source code for your PHP application.

If files are ready, jump in and get the PHP FPM, NGINX, and MySQL containers up and running.

For related setups, check the following:

Step 1: Creating PHP FPM Image using Dockerfile

Dockerfile will tell Docker how you need to package PHP and FPM. This is good when selecting the Version of PHP you want to run. Update your Dockerfile as follows:

# Add PHP-FPM base image
FROM php:8.2-fpm

# Install your extensions
# To connect to MySQL, add mysqli
RUN docker-php-ext-install mysqli pdo pdo_mysql
  • php:8.2-fpm is the base image and will run PHP version 8.2. You can update it with the right version.
  • docker-php-ext-install is a command for installing PHP extensions on Docker. Because you need to connect to MySQL mysqli, its extensions must be installed.

Step 2: Creating NGINX Image using Dockerfile

In your nginx/Dockerfile file, you’ll create the Docker configurations needed to package the NGINX server.

# Use the official NGINX image
FROM nginx:latest
# Remove default NGINX configuration
RUN rm /etc/nginx/conf.d/default.conf
# Copy your custom NGINX configuration
COPY ./nginx/nginx.conf /etc/nginx/conf.d/

You use the COPY command to add the nginx/nginx.conf file to Docker. This file contains all NGINX custom configurations you need to run and server PHP-FPM on docker.

Now open nginx/nginx.conf and add the following NGINX configurations:

server {
    listen 80;
    server_name localhost;

    root /var/www/html;
    index index.php index.html index.htm;

    # Redirects requests to index.php if the file is not found
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # Passes PHP requests to PHP-FPM container
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass php-fpm:9000; # Replace with your PHP-FPM container name
        fastcgi_index index.php;
    }

    # Logs for Nginx access and errors
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
}

By default, NGINX uses port 80. The server will run on localhost. We will use Docker Compose to add your app code to /var/www/html so Nginx can access it. The main file here is index.php. If you are using a different file name, update your configuration.

The location block adds routing for incoming requests.

The main part you need to understand is the location ~ \.php$ block. You need it to process PHP files. It forwards PHP requests to a php-fpm container and server your index.php file.

Based on that, PHP must be created with the php-fpm container name. You will create that in the next step.

Step 3: Creating PHP FPM and NGINX Containers with Docker Compose

Use the docker-compose.yml file to build the PHP FPM and NGINX images using the Dockerfiles you created. This way, Nginx will expose your app to the web so you can access it.

But first, ensure your app/index.php file has some static PHP-related code as follows:

<?php
echo "Testing PHP-FPM on Docker."
?>

<?php
phpinfo();
?>

Go to your docker-compose.yml file and create PHP-FPM and Nginx services as follows:

version: '3.9'
services:
  # PHP-FPM Service
  php-fpm:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
    # Mounts the local 'app' directory to the container's Nginx root
      - ./app:/var/www/html  

  # NGINX Service
  nginx:
    build:
      context: .
      dockerfile: ./nginx/Dockerfile
    volumes:
    # Mountlocal 'app' directory to the Nginx root
      - ./app:/var/www/html 
    ports:
      - "8080:80"
    depends_on:
      - php-fpm  # Depends on the PHP-FPM service

Run the following command to build and run your container:

docker-compose up --build -d

How to Deploy PHP FPM, NGINX, and MySQL with Docker Compose

How to Deploy PHP FPM, NGINX, and MySQL with Docker Compose

Open http://localhost:8080/ on the browser of your choice, and PHP-FPM is ready and running with Docker alongside NGINX as follows:

How to Deploy PHP FPM, NGINX, and MySQL with Docker Compose

And PHP, FPM, and NGINX are working with Docker Compose. Now, let’s add MySQL to run dynamic PHP code.

Step 4: Deploying PHP FPM, NGINX, and MySQL with Docker Compose

To Run PHP-FPM will MySQL, you need to create a MySQL service with Docker Compose. Update your docker-compose.yml file with MySQL as follows:

version: '3.9'
services:
  # PHP-FPM Service
  php-fpm:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
    # Mounts the local 'app' directory to the container's Nginx root
      - ./app:/var/www/html  
    depends_on:
    # Depends on the MySQL database service
      - mysql-db  

  # NGINX Service
  nginx:
    build:
      context: .
      dockerfile: ./nginx/Dockerfile
    volumes:
    # Mountlocal 'app' directory to the Nginx root
      - ./app:/var/www/html 
    ports:
      - "8080:80"
    depends_on:
      - php-fpm  # Depends on the PHP-FPM service
      - mysql-db  # Depends on the MySQL database service

  # MySQL Database Service
  mysql-db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: test_database
      MYSQL_USER: db_user
      MYSQL_PASSWORD: password
    ports:
    # Maps port 3306 on the host to port 3306 on the MySQL container
      - "3306:3306"  

Now, update the app/index.php file with MySQL-related dynamic PHP script as follows:

<?php
// Database connection parameters
$host = 'mysql-db';   // MySQL server hostname within the same Docker network
$user = 'db_user';    // MySQL username
$pass = 'password';   // MySQL password
$db = 'test_database';// MySQL database name

// Create a new MySQLi object to establish a database connection
$conn = new mysqli($host, $user, $pass, $db);

// Check if the connection was successful
if ($conn->connect_error) {
    // Display an error message and terminate the script if the connection fails
    die("Connection failed: " . $conn->connect_error);
}

// If the connection is successful, print a success message
echo "PHP Connected to MySQL successfully";

// Close the database connection
$conn->close();
?>

This script will create a connection. If the connection fails, it will display an error message indicating the failure reason. If the connection succeeds, it will print “PHP Connected to MySQL successfully” and then close the database connection using $conn->close().

That will be enough to test a PHP FPM, NGINX, and MySQL setup.

Run the Docker Compose command to rebuild your container:

docker-compose up --build -d

If your PHP FPM, NGINX, and MySQL setup work, http://localhost:8080/ should display a success message:

How to Deploy PHP FPM, NGINX, and MySQL with Docker Compose

Step 5: Deploying PhpMyAdmin to MySQL PHP-FPM NGINX Container

Now, how do you access, your database? PhpMyAdmin is great at doing that. Update the docker-compose.yml file with a PhpMyAdmin service as follows:

version: '3.9'
services:
  # PHP-FPM Service
  php-fpm:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
    # Mounts the local 'app' directory to the container's Nginx root
      - ./app:/var/www/html  
    depends_on:
    # Depends on the MySQL database service
      - mysql-db  

  # NGINX Service
  nginx:
    build:
      context: .
      dockerfile: ./nginx/Dockerfile
    volumes:
    # Mountlocal 'app' directory to the Nginx root
      - ./app:/var/www/html 
    ports:
      - "8080:80"
    depends_on:
      - php-fpm  # Depends on the PHP-FPM service
      - mysql-db  # Depends on the MySQL database service

  # MySQL Database Service
  mysql-db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: test_database
      MYSQL_USER: db_user
      MYSQL_PASSWORD: password
    ports:
    # Maps port 3306 on the host to port 3306 on the MySQL container
      - "3306:3306"  

  # PHPMyAdmin Service
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    links:
    # Links the PHPMyAdmin service to the MySQL database service
      - mysql-db 
    ports:
      - "8081:80" 
    environment:
      PMA_HOST: mysql-db
      # Use MySQL root password for PHPMyAdmin
      MYSQL_ROOT_PASSWORD: password 
  • Run the docker-compose command to rebuild and add the new service:
docker-compose up --build -d

PhpMyAdmin is exposed on 8081. Open http://localhost:8081/ to access it.

How to Deploy PHP FPM, NGINX, and MySQL with Docker Compose

  • Use root as the user and password as the password as set on MYSQL_ROOT_PASSWORD: password and login to phpMyAdmin:

How to Deploy PHP FPM, NGINX, and MySQL with Docker Compose

Conclusion

Congratulations! The PHP FPM, NGINX, and MySQL with Docker Compose setup work. You have learned how to deploy PHP FPM, NGINX, and MySQL using Docker Compose.

You have a working PHP FPM, NGINX, and MySQL environment. You can now effortlessly deploy your PHP code to Docker using Docker Compose.

How to Deploy PHP FPM, NGINX, and MySQL with Docker Compose

Written By:

Joseph Chege