Containerize Laravel with NGINX, MySQL, and MongoDB using Docker Containers

Containerize Laravel with NGINX, MySQL, and MongoDB using Docker Containers

It provides all the steps required to containerize the Laravel application using NGINX Web Server, MySQL, phpMyAdmin, MongoDB, and Mongo Express using Docker Containers.

December 31, 2021

We can containerize our applications using Docker to have a separate installation of the required packages with the application-specific versions independent of the underlying operating system. We can use Docker Containers to make our application portable so that we can simply move it to another system having docker. This tutorial provides all the steps to containerize a Laravel application using NGINX Web Server as the webserver and either MySQL or MongoDB or both as the database server.

Prerequisites

WindowsHow To Install WSL 2 (Windows Subsystem for Linux) with Ubuntu On Windows 10, How To Install Docker Desktop On Windows 10, and How To Install Composer As PHP Dependency Manager On Windows. Optionally you may follow How To Change Docker Data Path On Windows 10.

Ubuntu - How To Install Docker Engine on Ubuntu 20.04 LTS and How To Install Composer On Ubuntu 20.04

macOS - How To Install Docker Desktop On Mac

Install PHP, Laravel, and NGINX Web Server

Create a directory to store your project-specific files. I have created the directory helloworld to store all the project files. Now create the file docker-compose.yml at the root of your project directory as shown below.

# docker-compose.yml
version: "3.8"
services:
nginx:
container_name: nginx
build: ./docker/nginx
command: nginx -g "daemon off;"
links:
- php
ports:
- "80:80"
volumes:
- ./logs/nginx:/var/log/nginx
- ./src/helloworld:/var/www/html/helloworld
php:
container_name: php
build: ./docker/php
ports:
- "9000:9000"
volumes:
- ./src/helloworld:/var/www/html/helloworld
working_dir: /var/www/html/helloworld
composer:
container_name: composer
image: composer/composer
volumes:
- ./src/helloworld:/var/www/html/helloworld
working_dir: /var/www/html/helloworld
command: install

Now create the directories - docker and src within the project root directory. Also, create two directories within the docker directory i.e. php and nginx. Create the directories <project path>/logs/nginx to store the logs.

Create the Dockerfile within the PHP directory as shown below.

# docker/php/Dockerfile
FROM php:8.1-fpm

RUN apt-get update
RUN apt-get install -y openssl zip unzip git curl
RUN apt-get install -y libzip-dev libonig-dev libicu-dev
RUN apt-get install -y autoconf pkg-config libssl-dev

RUN docker-php-ext-install bcmath mbstring intl opcache

Create the Dockerfile within the NGINX directory as shown below.

# docker/nginx/Dockerfile
FROM nginx:1.20

We also need to configure the Server Block or Virtual Host to pass the PHP requests to PHP-FPM via port 9000. Now, create the default configuration file as shown below.

# docker/nginx/helloworld.nginx.conf
server {
listen 80;
index index.php index.htm index.html;

root /var/www/html/helloworld/public;

error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location ~ \.php$ {
try_files $uri =404;
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_param PATH_INFO $fastcgi_path_info;
}
}

Now, update the Dockerfile within the NGINX directory as shown below.

# docker/nginx/Dockerfile
FROM nginx:1.20
ADD helloworld.nginx.conf /etc/nginx/conf.d/default.conf

After creating all the directories and files, the directory structure should be similar as shown below.

helloworld
-- docker
-- php
-- Dockerfile
-- nginx
-- Dockerfile
-- helloworld.nginx.conf
-- src
-- <laravel app directories and files>
-- logs
-- nginx
-- docker-compose.yml

Next, we will install the Laravel project template files in the src directory using the command shown below. It's required for the first time for the fresh installation of Laravel.

# Clear Directory
cd <path to project>/src

# Install Laravel
composer create-project --prefer-dist laravel/laravel:^8.0 helloworld

# Output
Creating a "laravel/laravel:^8.0" project at "./helloworld"
Installing laravel/laravel (v8.77.1)
- Downloading laravel/laravel (v8.77.1)
- Installing laravel/laravel (v8.77.1): Extracting archive
Created project in E:\development\projects-study\php\docker\helloworld\src\helloworld
> @php -r "file_exists('.env') || copy('.env.example', '.env');"
Loading composer repositories with package information
Updating dependencies
....
....
Package manifest generated successfully.
77 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> @php artisan vendor:publish --tag=laravel-assets --ansi --force
No publishable resources for tag [laravel-assets].
Publishing complete.
> @php artisan key:generate --ansi
Application key set successfully.

The above command installs Laravel at <path to project>/src/helloworld.

Now, run the command docker-compose build to build the images for PHP and NGINX Web Server.

# Build
cd <path to project>
docker-compose build

# Output
Building php
[+] Building 3.6s (6/6) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 31B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/php:8.1-fpm 3.3s
=> [auth] library/php:pull token for registry-1.docker.io 0.0s
=> CACHED [1/1] FROM docker.io/library/php:8.1-fpm@sha256:c884ad419ce99d3136cd02a56f7ca84009fa5a50637e96d20acdd7 0.0s
=> exporting to image 0.1s
=> => exporting layers 0.0s
=> => writing image sha256:dd8e9ace979d52b810014bd90565f9bf60ffdbb754af263b1eb3b2bb5cc88648 0.0s
=> => naming to docker.io/library/helloworld_php 0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
Building nginx
[+] Building 3.4s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 31B 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/nginx:1.20 3.1s
=> [auth] library/nginx:pull token for registry-1.docker.io 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 43B 0.0s
=> [1/2] FROM docker.io/library/nginx:1.20@sha256:71a1217d769cbfb5640732263f81d74e853f101b7f2b20fcce991a22e68adb 0.0s
=> CACHED [2/2] ADD helloworld.nginx.conf /etc/nginx/conf.d/default.conf 0.0s
=> exporting to image 0.1s
=> => exporting layers 0.0s
=> => writing image sha256:9b1edf62e7a508b108c5043be42882327ec535269fac500e72267aa01512281d 0.0s
=> => naming to docker.io/library/helloworld_nginx 0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

After completing the build, we can run the application using the command shown below.

# Launch Application
docker-compose up

# Output
Creating network "helloworld_default" with the default driver
Creating php ... done
Creating nginx ... done
Attaching to php, nginx

Now open the browser and enter the URL - http://localhost. It should show Laravel's default, Welcome Page, as shown in Fig 1.

Containerize Laravel with PHP, NGINX, MySQL, and MongoDB using Docker - Home Page

Fig 1

Press Ctrl + C to stop the containers.

Install MySQL and phpMyAdmin

In this step, we will continue with our previous step and install MySQL and phpMyAdmin. We will also configure our laravel application to access the MySQL database. Now, update the docker-compose.yml as shown below.

# docker-compose.yml
version: "3.8"
services:
nginx:
container_name: nginx
build: ./docker/nginx
command: nginx -g "daemon off;"
links:
- php
ports:
- "80:80"
volumes:
- ./logs/nginx:/var/log/nginx
- ./src/helloworld:/var/www/html/helloworld
php:
container_name: php
build: ./docker/php
links:
- mysql
ports:
- "9000:9000"
volumes:
- ./src/helloworld:/var/www/html/helloworld
working_dir: /var/www/html/helloworld
composer:
container_name: composer
image: composer/composer
volumes:
- ./src/helloworld:/var/www/html/helloworld
working_dir: /var/www/html/helloworld
command: install
mysql:
image: mysql:8.0.27
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: '<root-password>'
MYSQL_DATABASE: helloworld
MYSQL_USER: helloworld
MYSQL_PASSWORD: '<db-password>'
ports:
- "3306:3306"
volumes:
- ./database/mysql:/var/lib/mysql
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: pma
links:
- mysql
environment:
PMA_HOST: mysql
PMA_PORT: 3306
PMA_ARBITRARY: 1
restart: always
ports:
- 8085:80

Now, install the PHP extensions to access MySQL from the PHP source files by updating the Dockerfile as shown below.

# docker/php/Dockerfile
FROM php:8.1-fpm

RUN apt-get update
RUN apt-get install -y openssl zip unzip git curl
RUN apt-get install -y libzip-dev libonig-dev libicu-dev
RUN apt-get install -y autoconf pkg-config libssl-dev

RUN docker-php-ext-install bcmath mbstring intl opcache

RUN docker-php-ext-install pdo pdo_mysql mysqli

Now configure the Laravel application to use the MySQL database by updating the files as shown below. You can also follow The Complete Guide To Perform CRUD Operations In Laravel Framework Using MySQL.

# Laravel Configurations
cd <path to project>/src/helloworld

# Update .env
....
....
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=helloworld
DB_USERNAME=root
DB_PASSWORD= '<root-password>'
....
....

We can also create other users and databases using phpMyAdmin. Now, run the command docker-compose build to build the application.

# Build
cd <path to project>
docker-compose build

# Output
mysql uses an image, skipping
phpmyadmin uses an image, skipping
Building php
....
....
=> => naming to docker.io/library/helloworld_nginx 0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

We also need to run the command docker-compose up to launch the application as shown below. It will pull the MySQL and phpMyAdmin images and take time for the first time. The subsequent launches will be faster.

# Launch Application
docker-compose up

# Output
Pulling mysql (mysql:8.0.27)...
8.0.27: Pulling from library/mysql
ffbb094f4f9e: Pull complete
df186527fc46: Pull complete
fa362a6aa7bd: Pull complete
5af7cb1a200e: Pull complete
....
....
Status: Downloaded newer image for mysql:8.0.27
Pulling phpmyadmin (phpmyadmin/phpmyadmin:)...
latest: Pulling from phpmyadmin/phpmyadmin
69692152171a: Pull complete
2040822db325: Pull complete
....
....
2e982de2b8e5: Pull complete
Digest: sha256:382dedf6b43bf3b6c6c90f355b4dda660beb3e099dqw1bb3241170e54fca6d59
Status: Downloaded newer image for phpmyadmin/phpmyadmin:latest
....
....
Creating mysql ... done
Recreating php ... done
Creating pma ... done
Recreating nginx ... done
Attaching to mysql, pma, php, nginx
....
....

Now, try to access phpMyAdmin from the Browser using the URL http://localhost:8085. It should show the phpMyAdmin home page as shown in Fig 2.

Containerize Laravel with PHP, NGINX, MySQL, and MongoDB using Docker - phpMyAdmin

Fig 2

Now, login to phpMyAdmin using the username as root and the root password configured in the docker-compose.yml. Also, leave the server blank. It should show the phpMyAdmin home page as shown in Fig 3.

Containerize Laravel with PHP, NGINX, MySQL, and MongoDB using Docker - phpMyAdmin

Fig 3

Now create the database tables using the artisan command as shown below.

# CD to Project Path
cd <path to project>

# List Files
docker-compose exec <php service name> ls -l

# Example
docker-compose exec php ls -l

# Output
total 300
-rwxrwxrwx 1 root root 4051 Dec 23 03:03 README.md
drwxrwxrwx 1 root root 4096 Dec 23 03:03 app
-rwxrwxrwx 1 root root 1686 Dec 23 03:03 artisan
drwxrwxrwx 1 root root 4096 Dec 23 03:03 bootstrap
....
....

# Migration Command
docker-compose exec <php service name> php artisan migrate

# Example
docker-compose exec php php artisan migrate

# Output
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (509.81ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (499.07ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (501.43ms)
Migrating: 2019_12_14_000001_create_personal_access_tokens_table
Migrated: 2019_12_14_000001_create_personal_access_tokens_table (992.00ms)

This completes the installation and configuration of MySQL and phpMyAdmin for the Laravel application.

Press Ctrl + C to stop the containers.

# Press Ctrl + C
Gracefully stopping... (press Ctrl+C again to force)
Stopping nginx ... done
Stopping php ... done
Stopping pma ... done
Stopping mysql ... done

Install MongoDB and MongoDB Express

In this step, we will continue with our previous step and install MongoDB and MongoDB Express. Now, update the docker-compose.yml as shown below.

# docker-compose.yml
version: "3.8"
services:
nginx:
container_name: nginx
build: ./docker/nginx
command: nginx -g "daemon off;"
links:
- php
ports:
- "80:80"
volumes:
- ./logs/nginx:/var/log/nginx
- ./src/helloworld:/var/www/html/helloworld
php:
container_name: php
build: ./docker/php
links:
- mysql
- mongo
ports:
- "9000:9000"
volumes:
- ./src/helloworld:/var/www/html/helloworld
working_dir: /var/www/html/helloworld
composer:
container_name: composer
image: composer/composer
volumes:
- ./src/helloworld:/var/www/html/helloworld
working_dir: /var/www/html/helloworld
command: install
mysql:
image: mysql:8.0.27
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: 'admin123'
MYSQL_DATABASE: helloworld
MYSQL_USER: helloworld
MYSQL_PASSWORD: 'admin123'
ports:
- "3306:3306"
volumes:
- ./database/mysql:/var/lib/mysql
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: pma
links:
- mysql
environment:
PMA_HOST: mysql
PMA_PORT: 3306
PMA_ARBITRARY: 1
restart: always
ports:
- 8085:80
mongo:
image: mongo:5.0
container_name: mongo
environment:
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=password
restart: unless-stopped
ports:
- "27017:27017"
volumes:
- ./database/mongodb/db:/data/db
- ./database/mongodb/dev.archive:/Databases/dev.archive
- ./database/mongodb/production:/Databases/production
command: [--auth]
mongo-express:
image: mongo-express
container_name: mexpress
environment:
- ME_CONFIG_MONGODB_ADMINUSERNAME=root
- ME_CONFIG_MONGODB_ADMINPASSWORD=password
- ME_CONFIG_MONGODB_URL=mongodb://root:password@mongo:27017/?authSource=admin
- ME_CONFIG_BASICAUTH_USERNAME=mexpress
- ME_CONFIG_BASICAUTH_PASSWORD=mexpress
links:
- mongo
restart: unless-stopped
ports:
- "8081:8081"

Replace the root password while configuring the docker-compose.yml. Also, install the PHP extensions to access MongoDB from the PHP source files by updating the Dockerfile as shown below.

# docker/php/Dockerfile
FROM php:8.1-fpm

RUN apt-get update
RUN apt-get install -y openssl zip unzip git curl
RUN apt-get install -y libzip-dev libonig-dev libicu-dev
RUN apt-get install -y autoconf pkg-config libssl-dev

RUN docker-php-ext-install bcmath mbstring intl opcache

RUN docker-php-ext-install pdo pdo_mysql mysqli

RUN pecl install mongodb
RUN echo "extension=mongodb.so" >> /usr/local/etc/php/conf.d/mongodb.ini

Also, configure the Laravel application to access the MongoDB database along with MySQL. You may skip MySQL and configure MongoDB as the only server depending on your requirements. You can also follow The Complete Guide To Perform CRUD Operations In Laravel Framework Using MongoDB.

# Laravel Configurations
cd <path to project>/src/helloworld

# MongoDB Extension for Laravel
composer require jenssegers/mongodb

# Update .env
....
....
MONGO_CONNECTION=mongodb
MONGO_HOST=mongo
MONGO_PORT=27017
MONGO_AUTH_DATABASE=admin
MONGO_DATABASE=helloworld
MONGO_USERNAME=root
MONGO_PASSWORD= '<password>'
....
....

Also, update the database configuration by updating config/database.php as shown below.

....
....
'default' => env('DB_CONNECTION', 'mysql'),
//'default' => env('DB_CONNECTION', 'mongodb'),
....
....
'connections' => [
....
....
'mongodb' => [
'driver' => 'mongodb',
'host' => env('MONGO_HOST'),
'port' => env('MONGO_PORT'),
'database' => env('MONGO_DATABASE'),
'username' => env('MONGO_USERNAME'),
'password' => env('MONGO_PASSWORD'),
'options' => [
'database' => env('MONGO_AUTH_DATABASE')
]
],
....
....

Now, configure the providers to use the MongoDB extension provided by Jens Segers by updating the config/app.php file as shown below.

....
....
'providers' => [
....
....
Jenssegers\Mongodb\MongodbServiceProvider::class
],
....
....

Now, run the build and up commands to again build the application and launch it. We can access MongoDB using the URL - http://localhost:8081. It will ask for the basic authentication configured by us. The home page should be similar as shown below.

Containerize Laravel with PHP, NGINX, MySQL, and MongoDB using Docker - Mongo Express

Fig 4

This completes the installation and configuration of MongoDB for the Laravel application.

Summary

This tutorial provided all the steps to containerize Laravel with NGINX Web Server, MySQL, phpMyAdmin, MongoDB, and MongoDB Express using Docker containers.

Write a Comment
Click the captcha image to get new code.
Discussion Forum by DISQUS