Setup Laravel, MySQL, phpMyAdmin with Docker Compose

Laravel is a PHP framework that is one of the most popular and widely used in the world today. And not without good cause, given its modularity and ease of scaling when using the mvc technique.

Docker, the container service that treats each container as its own lightweight, modular virtual machine, is ideal when you want to use each service without having to install it directly on your computer. In the event that you need to scale or test different services, the containers may be quickly swapped out.

When Laravel and Docker are used together, they form a strong combo for local development or for running several applications on a single server.

With Docker Compose, this How-To will show you how to set up a brand new Laravel application with MySQL 8.0 and phpMyAdmin on a Nginx webserver (LEMP) using Docker.

We will build up four containers (services) for the following purposes:

  • app (PHP 7.4 with dependencies)
  • Nginx webserver
  • MySQL 8.0 database
  • phpMyAdmin database admin

Additionally, make the database persistent between docker stop/restarts, and mount access.log and error.log to the host machine. Logging to the host machine makes it easier to access the logging.

Start by creating a new project directory in your home folder and enter it:

mkdir ~/myapplication
cd ~/myapplication

Set Up The Environment With Docker Compose

It is recommended that the user in the app service be identical to your system user in order to avoid permission conflicts when working with the application files.

To find out what your current user's uid is, type the following:

echo $UID # Output: 1000

Create the Dockerfile:

nano Dockerfile

The Dockerfile contains application settings, such as PHP version, dependencies and working directory.

It also creates the system user in the application and allows it to run artisan and composer commands.

Paste in the code below to create what will become our custom app image.

FROM php:7.4-fpm

# Arguments defined in docker-compose.yml
ARG user
ARG uid

# Install system dependencies
RUN apt-get update && apt-get install -y \
    git \
    curl \
    libpng-dev \
    libonig-dev \
    libxml2-dev \
    zip \

# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Install PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Create system user to run Composer and Artisan Commands
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
    chown -R $user:$user /home/$user

# Set working directory
WORKDIR /var/www

USER $user

To save your file in nano, just type ctrl + s, and then ctrl + x to exit.

Create the docker compose file:

nano docker-compose.yml

In this file we are defining the four Docker services we are gonna use;

  • app, application settings.
  • nginx, webserver.
  • db, MySQL database.
  • phpmyadmin, UI for the database.

The custom app image is built by the Dockerfile we created above, and the other three services are pulled from docker hub.

Paste in the code below and remember to update user and it's uid to match your system user.

version: "3.7"
        user: aker
        uid: 1000
      context: ./
      dockerfile: Dockerfile
    image: myapplication-app
    restart: unless-stopped
    working_dir: /var/www/
      - ./:/var/www
      - myapplication

    image: nginx:alpine
    restart: unless-stopped
      - 80:80
      - ./:/var/www
      - ./nginx/conf.d/:/etc/nginx/conf.d/
      - ./nginx/ssl/:/etc/nginx/ssl/
      - /var/log/nginx/:/var/log/nginx/
      - myapplication

    image: mysql:8
    restart: unless-stopped
      - dbdata:/var/lib/mysql/
      - myapplication

    image: phpmyadmin/phpmyadmin
    restart: always
      - db
      - "8081:80"
      PMA_HOST: db
      - myapplication

    driver: bridge

    driver: local

Although the nginx webserver is now running on port 80, it can be configured to run on any available port, such as 8080, if desired.

To start up the app service in detached mode (d- means running in the background), type:

docker-compose up -d app

To verify that the service(s) are up and running, type:

docker-compose ps


       Name                      Command              State    Ports
myapplication_app_1   docker-php-entrypoint php-fpm   Up      9000/tcp

Install Laravel

Laravel is retrieved by executing composer through the app service, which is invoked by the composer command. The files will be downloaded and saved to a folder named application:

docker-compose exec app composer create-project laravel/laravel --prefer-dist application

Next, copy the application files to the same directory as the docker-compose.yml file. Then, you can remove the application directory:

cp -rT application .
rm -rfv application

The database credentials and environment variables are defined in the .env file, open it by typing:

nano .env

Several of the fields have already been completed.

It is strongly recommended that at the very least DB USERNAME be changed to something other than root, because the root account will be created when we build our docker services anyhow.

Because we will be configuring the DB HOST variable to point to the db service (specified in the docker-compose.yml file), we will modify it to db instead of, as seen in the example below.

You can use the example below, but make sure to change the DB PASSWORD field to something more safe before using it.




To create the directory for the nginx settings, type:

mkdir -p nginx/conf.d

The webserver configuration file app.conf will be stored in the directory conf.d.

Create the nginx configuration file:

nano nginx/conf.d/app.conf

And paste in the code below:

server {
    listen 80;

    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/public;
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    location / {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;

You may now bring up the remainder of the services, such as nginx, db and phpmyadmin by typing the following:

docker-compose up -d

If everything has gone according to plan, you should now see this screen when you navigate to localhost (or your domain) in your web browser.

Image of Laravel dashboard

phpMyAdmin can be found at the following address: (yourdomain):8081.

To log in, simply enter your DB_USERNAME and DB_PASSWORD from your .env file into the appropriate fields.

If you want to connect with higher rights, simply login as root instead of your username; the password for root should be the same as for your username.

Image of php my admin dashboard

The database, with all of its contents, will remain accessible between docker restarts and stops.

This is due to the fact that we mounted the database on our host computer, which was specified in the docker-compose.yml file as follows:

      - dbdata:/var/lib/mysql/

    driver: local

Access Log Files, access.log and error.log

The log files are stored on your host for easy access because we mounted the /var/log/nginx/ path to your host (with the same path) under the nginx service in the docker-compose.yml file.

      - /var/log/nginx/:/var/log/nginx/

The access.log file contains a record of all requests made to your application, including those made from IP addresses, URLs with arguments, and status codes.

The error.log is where Nginx keeps track of any issues that arise. These issues fall into the following categories: debug, info, notice, warn, and error.

You can view your nginx server logs by entering the following command:

tail /var/log/nginx/access.log
tail /var/log/nginx/error.log

Working With Docker Commands

Each system command must be executed from within the container because the application is running within the docker environment.

For example, if you want to migrate using artisan, you can run the following instructions through the app container.

docker-compose exec app php artisan migrate

Alternatively, composer can be used in the similar way:

docker-compose exec app composer dump-autoload

Alternatively, composer install can be used if you have packages to install.

Stopping a single container, such as the phpmyadmin container, is accomplished as follows:

(Just replace stop with start if you want it to start it again).

docker-compose stop phpmyadmin

To take down all of your services, removing all containers as well as any networks that were created, type:

Note: The database will not be deleted because we mounted it to the host and made it persistent, so when you restart the containers, the database and all of its contents will still be there for you to access.

docker-compose down