Laravel Development Environment with Docker and Docker Compose: A Step-by-Step Tutorial
Published: 2024-01-29 12:49:00


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9mwt7itl3j9k9dqz9552.png)

Laravel, the PHP web application framework, and Docker, the containerization platform, are a match made in heaven for developers seeking scalability, efficiency, and ease of deployment. In this extensive guide, we’ll delve deep into the integration of Laravel with Docker, exploring the intricacies of setting up a robust environment and establishing seamless communication between two Laravel projects.

Here’s a list of the services we’ll be creating in our Docker environment —
- PHP — 8.2-fpm-alpine
- Nginx — nginx:stable-alpine
- MySQL — mysql:8.0.1
- Mailhog
- PhpMyAdmin

## 
Step 1 — Download & Install Docker

Prerequisites:
Before you begin, ensure that your system meets the following requirements:
• A compatible operating system (Linux, macOS, or Windows)
• Administrative privileges (for installation)
• Internet connection to download Docker

Download Docker:
Visit the official Docker website to download the Docker Desktop application. Navigate to [https://www.docker.com/get-started](https://www.docker.com/get-started) and click on the “Download for [Your OS]” button.

Install Docker:
Once the download is complete, follow these steps for your specific operating system:

For Windows:
• Run the installer you downloaded.
• Follow the on-screen instructions to install Docker Desktop.
• During installation, you may be asked to enable Hyper-V. Allow this to ensure proper functioning of Docker containers on Windows.

For macOS:
• Open the downloaded .dmg file.
• Drag the Docker icon to the Applications folder.
• Open Docker from the Applications folder and follow any additional prompts to complete the installation.

For Linux:
• Refer to the Docker documentation for instructions tailored to your Linux distribution: [https://docs.docker.com/install/](https://docs.docker.com/install/)

Verify Installation:

After the installation is complete, verify that Docker is running correctly:
• Open a terminal or command prompt.
• Type the following command and press Enter:

```Docker --version
```

This should display the installed Docker version, confirming a successful installation.
• To ensure Docker is running, enter:

```Docker run hello-world
```
Docker run hello-world
If everything is set up correctly, you will see a message indicating that your Docker installation is working.

## Step 2 — Setting Up Laravel Projects in Docker File

Docker Compose Configuration

Start by creating a Dockerfile in the root directory of your Laravel project. This file will contain instructions for building a Docker image.

Configure the Nginx Server in DockerFile

```
services:
  server:
    build:
      context: .
      dockerfile: dockerfiles/nginx.dockerfile
    ports:
      - 8080:80
    volumes:
      - ./src:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - php
      - redis
      - mysql
      - mailhog
    container_name: laravel_enviroment_server
    networks:
      - laravel_enviroment
```


These settings do the following:

• **build**: This configuration tells Docker Compose to build a local image for the app service, using the specified path (context) and Dockerfile for instructions. The arguments user and uid are injected into the Dockerfile to customize user creation commands at build time.

• **image**: The name that will be used for the image being built..

• **ports**: Defines a port redirection that will allow external access through port 8000 to the web server running on port 80, inside the container.

• **volumes**: Creates a shared volume that will synchronize contents from the current directory to /var/www/html inside the container. Notice that this is not your document root, since that will live in the nginx container.

• **networks**: Sets up this service to use a networkname mysql_laravel_enviroment.

These settings do the following:

• build: This configuration tells Docker Compose to build a local image for the app service, using the specified path (context) and Dockerfile for instructions. The arguments user and uid are injected into the Dockerfile to customize user creation commands at build time.

• image: The name that will be used for the image being built..

• ports: Defines a port redirection that will allow external access through port 8000 to the web server running on port 80, inside the container.

• volumes: Creates a shared volume that will synchronize contents from the current directory to /var/www/html inside the container. Notice that this is not your document root, since that will live in the nginx container.

• networks: Sets up this service to use a networkname mysql_laravel_enviroment.

Setting /nginx/default.conf


```
FROM nginx:stable-alpine
 
 WORKDIR /etc/nginx/conf.d
 
 COPY nginx/default.conf .
 
 RUN mv default.conf default.conf
 
 WORKDIR /var/www/html
 
 COPY src .
```

Setting nginx.conf

```
server {
    listen 80;
    index index.php index.html;
    server_name localhost;
    root /var/www/html/public;
    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;
    }
}
```

These settings do the following:

• listen: This directive defines the port on which the server will listen to incoming requests.
• root: This directive sets the root folder path, forming the complete path to any requested file on the local file system.

Setting PHP

```
php:
    build:
      context: .
      dockerfile: dockerfiles/php.dockerfile
    volumes:
      - ./src:/var/www/html:delegated
    container_name: php_laravel_enviroment
    networks:
      - laravel_enviroment
```


Setting php.dockerfile

```
FROM php:8.2-fpm-alpine

WORKDIR /var/www/html

COPY src .
# Instalando extensões necessárias do PHP
RUN apk add --no-cache mysql-client msmtp perl wget procps shadow libzip libpng libjpeg-turbo libwebp freetype icu

RUN apk add --no-cache --virtual build-essentials \
    icu-dev icu-libs zlib-dev g++ make automake autoconf libzip-dev \
    libpng-dev libwebp-dev libjpeg-turbo-dev freetype-dev && \
    docker-php-ext-configure gd --enable-gd --with-freetype --with-jpeg --with-webp && \
    docker-php-ext-install gd && \
    docker-php-ext-install mysqli && \
    docker-php-ext-install pdo_mysql && \
    docker-php-ext-install intl && \
    docker-php-ext-install bcmath && \
    docker-php-ext-install opcache && \
    docker-php-ext-install exif && \
    docker-php-ext-install zip && \
    apk del build-essentials && rm -rf /usr/src/php*

RUN apk add --no-cache pcre-dev $PHPIZE_DEPS \
        && pecl install redis \
        && docker-php-ext-enable redis.so

RUN addgroup -g 1000 laravel && adduser -G laravel -g laravel -s /bin/sh -D laravel

RUN chown -R laravel /var/www/html

USER laravel
first the Dockerfile creates an image on top of the php:8.2-fpm-alpine .
```

The file also installs the prerequisite packages for Laravel: pdo_mysql, mbstring, mcrypt , gd, mysqli , and imagick with composer.

The RUN directive specifies the commands to update, install, and configure settings inside the container, including creating a dedicated user and group called www/html .

The WORKDIR instruction specifies the /var/www/html directory as the working directory for the application.

Creating a dedicated user and group called laravel , with restricted permissions mitigates the inherent vulnerability when running Docker containers, which run by default as root.

Setting Mysql


```
mysql:
    image: mysql:8.0.1
    restart: unless-stopped
    tty: true
    container_name: mysql_laravel_enviroment
    env_file:
      - mysql/.env
    ports:
      - 3306:3306
    networks:
      - laravel_enviroment
    volumes:
      - /opt/mysql_data:/var/lib/mysql
```

• Defines the Docker image that should be used for this container. In this case, we’re using a MySQL 8.0.1 image from Docker Hub.

• container_name: Sets up the container name for this service: travellist-db.
• restart: Always restart this service, unless it is explicitly stopped.

volumes: Creates a volume to share a .sql database dump that will be used to initialize the application database. The MySQL image will automatically import .sql files placed in the /var/lib/mysq directory inside the container.
• networks: Sets up this service to use a networkname mysql_laravel_enviroment.
Setting Mysql .env


```MYSQL_DATABASE=laravel_project
MYSQL_USER=homestead
MYSQL_PASSWORD=secret
MYSQL_ROOT_PASSWORD=secret
```

MYSQL_DATABASE will be the database.
• MYSQL_USER will be the username you will use for your database. In this case, we will use .
• MYSQL_PASSWORD will be the secure password you would like to use for this user account.
• MYSQL_ROOT_PASSWORD will be the mysql root password .


Setting composer

```
composer:
    build:
      context: ./dockerfiles
      dockerfile: composer.dockerfile
    volumes:
      - ./src:/var/www/html
    depends_on:
      - php
    networks:
      - laravel_enviroment
```


Setting All composer.dockerfile

```
FROM composer:latest
 
RUN addgroup -g 1000 laravel && adduser -G laravel -g laravel -s /bin/sh -D laravel
 
USER laravel
 
WORKDIR /var/www/html
 
ENTRYPOINT [ "composer", "--ignore-platform-reqs" ]



version: "3.9"

networks:
  laravel_enviroment:

services:
  server:
    build:
      context: .
      dockerfile: dockerfiles/nginx.dockerfile
    ports:
      - 8080:80
    volumes:
      - ./src:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - php
      - redis
      - mysql
      - mailhog
    container_name: laravel_enviroment_server
    networks:
      - laravel_enviroment
  php:
    build:
      context: .
      dockerfile: dockerfiles/php.dockerfile
    volumes:
      - ./src:/var/www/html:delegated
    container_name: php_laravel_enviroment
    networks:
      - laravel_enviroment
  mysql:
    image: mysql:8.0.1
    restart: unless-stopped
    tty: true
    container_name: mysql_laravel_enviroment
    env_file:
      - mysql/.env
    ports:
      - 3306:3306
    networks:
      - laravel_enviroment
    volumes:
      - /opt/mysql_data:/var/lib/mysql
  phpmyadmin:
    image: phpmyadmin/phpmyadmin:latest
    restart: always
    container_name: phpmyadmin_laravel_enviroment
    depends_on:
      - mysql
    ports:
      - '8891:80'
    environment:
      - PMA_HOST=mysql
      - PMA_USER=root
      - PMA_PASSWORD=secret
    networks:
      - laravel_enviroment
  redis:
    image: redis:alpine
    container_name: redis_laravel_enviroment
    restart: unless-stopped
    ports:
      - 6379:6379
    networks:
      - laravel_enviroment
    command: redis-server --appendonly yes --replica-read-only no

  composer:
    build:
      context: ./dockerfiles
      dockerfile: composer.dockerfile
    volumes:
      - ./src:/var/www/html
    depends_on:
      - php
    networks:
      - laravel_enviroment
  artisan:
    build:
      context: .
      dockerfile: dockerfiles/php.dockerfile
    volumes:
      - ./src:/var/www/html
    entrypoint: ["php", "/var/www/html/artisan"]
      #depends_on:
    #- mysql
    networks:
      - laravel_enviroment
  scheduler:
    build:
      context: .
      dockerfile: dockerfiles/php.dockerfile
    container_name: scheduler_laravel_enviroment
    volumes:
      - ./src:/var/www/html
    working_dir: /var/www/html
    entrypoint: [ "php", "artisan", "schedule:work" ]
    networks:
      - laravel_enviroment
  mailhog:
    image: mailhog/mailhog:latest
    container_name: mailhog_laravel_enviroment
    ports:
      - 1025:1025
      - 8025:8025
    networks:
      - laravel_enviroment
```


The extructure will be like this


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7vcyes9th4cg7kcje6ha.png)

## Step 3 — Run those Containers

```
docker-compose up -d
```



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qww5p8je4az3pklip8k3.png)



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s56m7djvt6qzkgxo9vem.png)

## Step 4— Create Laravel Project and Set Database

```
docker-compose run --rm composer create-project laravel/laravel .
```


Access PHP My Admin


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vljjbi8y3fxe1p6sqzwq.png)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/92hcwjc4ljrhvuhxgwly.png)

Access phpmyadmin and create the Db -laravel_db ( the same name that is on mysql.env — MYSQL_DATABASE=laravel_db )

Set Laravel .env

```
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laravel_db
DB_USERNAME=root
DB_PASSWORD=secret

```

DB_host with must be the same name of the configuration in dockerfile

Clear the config cache

```
docker-compose run --rm artisan config:cache

```

Migrate Database

```
docker-compose run  --rm artisan migrate
```



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7qrz1a9qefuj2jrifgf5.png)

## Step 5 — Access the Project

Access the url — localhost:8080
The url with the same name of the configuration server in dockerfile -


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/09czo3m1ufyd0smwltoj.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2zfejtmuc559hlkwj9wy.png)


## Conclusion:
Congratulations! You’ve successfully set up a Laravel development environment using Docker and Docker Compose. This approach ensures consistency across different development machines and simplifies the process of managing dependencies. As you continue developing your Laravel application, you can extend and customize this setup to suit your specific project requirements. Happy coding!

## Git Hub Code -
[https://github.com/murilolivorato/laravel_docker_enviroment](https://github.com/murilolivorato/laravel_docker_enviroment)


Thanks a lot for reading till end. Follow or contact me via:
Github:[https://github.com/murilolivorato
](https://github.com/murilolivorato
)LinkedIn: [https://www.linkedin.com/in/murilo-livorato-80985a4a/](https://www.linkedin.com/in/murilo-livorato-80985a4a/)
Youtube : [https://www.youtube.com/@murilolivorato1489](https://www.youtube.com/@murilolivorato1489)