Docker is an open-source containerization tool that allows you to create, deploy, and run applications using containers. Containers allow you to package an application with all required parts and deploy it as a single package. Containers are portable, and you can deploy them anywhere. A container brings developers a uniform and streamlined work environment that can be easily shared.
This guide will show you how to deploy a PHP application with Nginx and MySQL using Docker and Docker Compose.
Step 1 – Install Docker and Docker Compose
By default, the latest version of Docker is not included in the Ubuntu default repository, so you will need to add the Docker repository to your system.
First, install the required dependencies using the following commands:
apt-get update -y
apt-get install apt-transport-https ca-certificates curl tree software-properties-common -y
Next, add the Docker repository using the following command:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
Next, install the Docker and Docker Compose with the following command:
apt-get install docker-ce docker-compose -y
Once you are finished, you can proceed to the next step.
Step 2 – Directory Structure
For this tutorial, we will use the following directory structure:
/root/docker-project/ ├── docker-compose.yml ├── nginx │ ├── default.conf │ └── Dockerfile ├── php │ └── Dockerfile └── www └── html └── index.php
Step 3 – Create an Nginx Container
Before starting, you must create and launch an Nginx container to host the PHP application.
First, create a directory for your project with the following command:
mkdir ~/docker-project
Next, change the directory to your project and create a docker-compose.yml file to launch the Nginx container.
cd ~/docker-project nano docker-compose.yml
Add the following lines:
nginx: image: nginx:latest container_name: nginx-container ports: - 80:80
Save and close the file when you are finished.
The above file will download the latest Nginx image, create an Nginx container, and expose it on port 80.
Next, launch the Nginx container with the following command:
docker-compose up -d
You can check the running container with the following command:
docker ps
You should see the following output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c6641e4d5bbf nginx:latest "/docker-entrypoint.…" 5 seconds ago Up 3 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp nginx-container
Now, open your web browser and access your Nginx container using the URL http://your-server-ip. You should see the Nginx test page on the following screen:
Step 4 – Create a PHP Container
First, create a new directory inside your project with the following command:
mkdir -p ~/docker-project/www/html
Next, create an index.php file to verify your PHP version.
nano ~/docker-project/www/html/index.php
Add the following lines:
<!DOCTYPE html> <head> <title>Hello World!</title> </head> <body> <h1>Hello World!</h1> <p><?php echo 'We are running PHP, version: ' . phpversion(); ?></p> </body>
Save and close the file, then create a directory for Nginx inside your project directory:
mkdir ~/docker-project/nginx
Next, create an Nginx default configuration file to run your PHP application:
nano ~/docker-project/nginx/default.conf
Add the following lines:
server { listen 80 default_server; root /var/www/html; index index.html index.php; charset utf-8; location / { try_files $uri $uri/ /index.php?$query_string; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } access_log off; error_log /var/log/nginx/error.log error; sendfile off; client_max_body_size 100m; location ~ .php$ { fastcgi_split_path_info ^(.+.php)(/.+)$; fastcgi_pass php:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_intercept_errors off; fastcgi_buffer_size 16k; fastcgi_buffers 4 16k; } location ~ /.ht { deny all; } }
Save and close the file.
Next, create a Dockerfile inside the nginx directory. This will copy the Nginx default config file to the Nginx container.
nano ~/docker-project/nginx/Dockerfile
Add the following lines:
FROM nginx:latest COPY ./default.conf /etc/nginx/conf.d/default.conf
Next, edit the docker-compose.yml file:
nano ~/docker-project/docker-compose.yml
Remove the old contents and add the following contents:
---
nginx:
build: ./nginx/
container_name: nginx-container
ports:
- 80:80
links:
- php
volumes:
- ./www/html/:/var/www/html/
php:
image: php:7.0-fpm
container_name: php-container
expose:
– 9000
volumes:
– ./www/html/:/var/www/html/
Save and close the file when you are finished.
The above file will create a new PHP-container, expose PHP-FPM on port 9000, link nginx-container to php-container, create a volume, and mount it on the container so that all content will be in sync with the container’s directory /var/www/html/.
Now, launch the container with the following command:
cd ~/docker-project docker-compose up -d
You can verify the running containers with the following command:
docker ps
You should see the following output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 82c8baf15221 docker-project_nginx "/docker-entrypoint.…" 23 seconds ago Up 22 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp nginx-container 10778c6686d8 php:7.0-fpm "docker-php-entrypoi…" 25 seconds ago Up 23 seconds 9000/tcp php-container
Now, open your web browser and access the URL http://your-server-ip. You should see your Hello World page:
Next, we will check whether our mounted volume works or not. To do so, edit the index.php file:
nano ~/docker-project/www/html/index.php
Change the line “Hello World! Changes are Applied”:
<!DOCTYPE html> <head> <title>Hello World!</title> </head> <body> <h1>Hello World! Changes are Applied</h1> <p><?php echo 'We are running PHP, version: ' . phpversion(); ?></p> </body>
Now, refresh your web page. You should see your modified page on the screen:
Step 5 – Create a Data Container
As you can see, we have mounted the directory www/html to our containers, nginx-container, and php-container. However, this is not a proper way. This section will create a separate data container to hold the data and link it to all other containers.
To do so, edit the docker-compose.html file:
nano ~/docker-project/docker-compose.yml
Make the following changes:
nginx: build: ./nginx/ container_name: nginx-container ports: - 80:80 links: - php volumes_from: - app-data php: image: php:7.0-fpm container_name: php-container expose: - 9000 volumes_from: - app-data app-data: image: php:7.0-fpm container_name: app-data-container volumes: - ./www/html/:/var/www/html/ command: "true"
Now, recreate and launch all containers using the following command:
cd ~/docker-project docker-compose up -d
Now, verify all running containers with the following command:
docker ps -a
You should see the following output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 849315c7ffc0 docker-project_nginx "/docker-entrypoint.…" 27 seconds ago Up 25 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp nginx-container 59a0d7040fd8 php:7.0-fpm "docker-php-entrypoi…" 28 seconds ago Up 27 seconds 9000/tcp php-container fbca95944234 php:7.0-fpm "docker-php-entrypoi…" 29 seconds ago Exited (0) 28 seconds ago app-data-container
Step 6 – Create a MySQL Container
This section will create a MySQL database container and link it to all other containers.
First, you must modify the PHP image and install the PHP extension for MySQL to connect to the MySQL database.
First, create a directory for PHP with the following command:
mkdir ~/docker-project/php
Next, create a Dockerfile to install the PHP extension:
nano ~/docker-project/php/Dockerfile
Add the following lines:
FROM php:7.0-fpm RUN docker-php-ext-install pdo_mysql
Save and close the file. Then, edit the docker-compose.yml file to create a MySQL container and MySQL data container to hold the database and tables:
nano ~/docker-project/docker-compose.yml
Make the following changes:
nginx: build: ./nginx/ container_name: nginx-container ports: - 80:80 links: - php volumes_from: - app-data php: build: ./php/ container_name: php-container expose: - 9000 links: - mysql volumes_from: - app-data app-data: image: php:7.0-fpm container_name: app-data-container volumes: - ./www/html/:/var/www/html/ command: "true" mysql: image: mysql:5.7 container_name: mysql-container volumes_from: - mysql-data environment: MYSQL_ROOT_PASSWORD: secret MYSQL_DATABASE: mydb MYSQL_USER: myuser MYSQL_PASSWORD: password mysql-data: image: mysql:5.7 container_name: mysql-data-container volumes: - /var/lib/mysql command: "true"
Save and close the file.
Next, edit the index.php file and make changes to test the database connection.
nano ~/docker-project/www/html/index.php
Make the following changes:
<!DOCTYPE html> <head> <title>Hello World!</title> </head> <body> <h1>Hello World!</h1> <p><?php echo 'We are running PHP, version: ' . phpversion(); ?></p> <? $database ="mydb"; $user = "myuser"; $password = "password"; $host = "mysql"; $connection = new PDO("mysql:host={$host};dbname={$database};charset=utf8", $user, $password); $query = $connection->query("SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_TYPE='BASE TABLE'"); $tables = $query->fetchAll(PDO::FETCH_COLUMN); if (empty($tables)) { echo "<p>There are no tables in database \"{$database}\".</p>"; } else { echo "<p>Database \"{$database}\" has the following tables:</p>"; echo "<ul>"; foreach ($tables as $table) { echo "<li>{$table}</li>"; } echo "</ul>"; } ?> </body> </html>
Save and close the file, then launch the container with the following command:
cd ~/docker-project docker-compose up -d
Verify all running containers with the following command:
docker ps -a
You should see the following output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d3e82747fe0d mysql:5.7 "docker-entrypoint.s…" 39 seconds ago Up 38 seconds 3306/tcp, 33060/tcp mysql-container 606320e5a7f8 mysql:5.7 "docker-entrypoint.s…" 41 seconds ago Exited (0) 39 seconds ago mysql-data-container ca4f63797d11 docker-project_php "docker-php-entrypoi…" 2 hours ago Up 2 hours 9000/tcp php-container 849315c7ffc0 docker-project_nginx "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:80->80/tcp, :::80->80/tcp nginx-container fbca95944234 php:7.0-fpm "docker-php-entrypoi…" 2 hours ago Exited (0) 39 seconds ago app-data-container
Step 7 – Verify Database Connection
Now, open your web browser and access the web page at http://your-server-ip. You should see the following screen:
As you can see, there are no tables in the mydb database.
However, there are, in fact, some tables that are not visible to a regular user. If you want to see them, edit the index.php file and change $user to “root” and $password to “secret.”
nano ~/docker-project/www/html/index.php
Change the following line:
$user = "root"; $password = "secret";
Save and close the file, then refresh the page. You should see the database with all tables on the following screen:
Conclusion
In the above guide, you learned how to deploy a PHP application with Nginx and MySQL using Docker and Docker Compose. You should now be able to host the PHP application in the production environment with Docker; try it on your VPS hosting account from Atlantic.Net.