Docker: Dockerize Laravel Application

We need to run 2 main containers for running a Laravel application-

  • PHP FPM – for running and processing the PHP code code of Laravel
  • Nginx – for serving the processed result from PHP FPM to the user

We also need to run a NodeJS container, for processing the UI using Vite.

WARNING

You do not need the NodeJS container if you do require the UI processing, or you are only developing Backend API with Laravel.

NOTE

Additionally, we are running a MySQL container for the database part. But this is not a required part of Laravel containerizing.

Required files

We need the following files to dockerize a Laravel application.

PurposeDockerfileConfig file
PHP FPMphp.Dockerfilephp.inidocker/php/php.Dockerfile
docker/php/php.ini
Nginxnginx.confdocker/nginx/nginx.conf
NodeJS(for UI using Vite)node.Dockerfiledocker/node/node.Dockerfile

Docker Files

  • php.Dockerfile – Dockerfile for the PHP container
  • node.Dockerfile – Dockerfile for the Node container

NOTE

We are using the standard image for Nginx.

Config Files

  • php.ini – PHP configuration file
  • nginx.conf – Nginx configuration file

Directory Structure

Here is the directory structure and file, we are using-

Laravel Project Root
    |
    |-docker
    |   |
    |   |-nginx
    |   |   |
    |   |   |-nginx.conf
    |   |
    |   |-node
    |   |   |
    |   |   |-node.Dockerfile
    |   |   
    |   |-php
    |   |   |
    |   |   |-php.Dockerfile
    |   |   |-php.ini
    |   |   
    |-docker-compose.yml

WARNING

We have created a separate directory named “docker” and keeping all docker-related files inside it.

You can keep all these files in your preferred location/directory, even in the root directory.

PHP FPM Setup

Create a file named php.Dockerfile, at location docker/php/php.Dockerfile. In the Dockerfile-

Pull the standard composer image.
Pull from PHP FPM image. Here we are using image for PHP version 8.3, you can use your preferred version.
Use work directory /var/www.
Install required packages, like zip, curl, git, etc.
Install PHP extensions – pdo, pgsql, pdo_pgsql, pdo_mysql, mbstring, exif, pcntl, bcmath, gd, zip, intl, opcache, etc.
Copy the php.ini to the container directory /usr/local/etc/php
Get the composer executable from the composer image, from location /usr/bin/composer. And copy it to the PHP FPM image.
Set permissions for files and directories.
Finally, run the “php-fpm“.
# docker/php/php.Dockerfile

# Pull the composer image
FROM composer:latest as composer

# Pull the PHP fpm image
FROM php:8.3-fpm

# Set working directory
WORKDIR /var/www

# Install dependencies
RUN apt-get update && apt-get install -y \
    build-essential \
    libpng-dev \
    libonig-dev \
    libxml2-dev \
    zip \
    curl \
    unzip \
    git \
    libzip-dev \
    libfreetype6-dev \
    libjpeg62-turbo-dev \
    libpng-dev \
    libpq-dev \
    && docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \
    && docker-php-ext-install pdo pgsql pdo_pgsql pdo_mysql mbstring exif pcntl bcmath gd zip intl opcache

# Copy php.ini to the container
COPY ./docker/php/php.ini /usr/local/etc/php

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

# Enable the following 2 commands if imagick extension is required
# RUN apt-get update && apt-get install -y libmagickwand-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*

# RUN mkdir -p /usr/src/php/ext/imagick; \
#     curl -fsSL https://github.com/Imagick/imagick/archive/06116aa24b76edaf6b1693198f79e6c295eda8a9.tar.gz | tar xvz -C "/usr/src/php/ext/imagick" --strip 1; \
#     docker-php-ext-install imagick;


# Remove default server definition
RUN rm -rf /var/www/html

# Install Composer
COPY --from=composer /usr/bin/composer /usr/bin/composer

# Copy existing application directory contents
COPY . .

# Install application dependencies
RUN composer install

# Copy existing application directory contents
RUN chown -R www-data:www-data /var/www

# Change current user to www
USER www-data

# Expose port 9000 and start php-fpm server
EXPOSE 9000

CMD ["php-fpm"]

WARNING

Here we have extensions that you might not require. So remove those, which are not required in your case.

Like, here we have extensions for MySQL and PGSQL both. Only use the extensions that you require.

Create configuration file docker/php/php.ini. This INI file will be used to add our custom configuration for PHP. We can add any PHP related configuration here-

; General
upload_max_filesize=20M
post_max_size=20M
INI

NOTE

If you do not need a custom php.ini file then ignore this file, and also remove the line that copies the INI file from the PHP Dockerfile(php.Dockerfile)-

# php.Dockerfile

# Remove the following line if not required
COPY ./docker/php/php.ini /usr/local/etc/php
Dockerfile

Nginx Setup

As we are using the standard image for Nginx, so we would not need a separate Dockerfile for Nginx.

Create file docker/nginx/nginx.conf and add the following configuration-

Expose the service to port 80. It will be exposed on port 80 of the container.
In the fasetcgi_pass configuration, we are getting the output from the PHP FPM from port 9000.
# docker/nginx/nginx.conf

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;

    send_timeout 300s;
    proxy_read_timeout 300s;
    fastcgi_read_timeout 300s;

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

    location ~ \.php$ {
        fastcgi_pass php:9000; #name of the sevice that runs the laravel app in docker-compose.yml file
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    location ~ /\.ht {
        deny all;
    }
}

NodeJS Setup(for UI using Vite)

Create file docker/node/node.Dockerfile and add the steps for building Node image-

Take the standard image for the Node container. You can use the Alpine image or any other image if you prefer.
Use /var/www as the working directory.
Copy package.json and package-lock.json to the container working directory.
Run “npm install“.
Finally, run the command “npm run dev“.
# docker/node/node.Dockerfile

# Set the base image
FROM node:latest

# Set working directory
WORKDIR /var/www

# Copy `package.json` and `package-lock.json`
COPY package*.json ./

# Install project dependencies
RUN npm install

# Copy project files into the docker image
COPY . .

# Expose the port Vite runs on
EXPOSE 3000

# Start the Vite server
CMD ["npm", "run", "dev"]

NOTE

Ignore the NodeJS setup if not required in your case.

Docker Compose Setup

Create a file named docker-compose.yml if the product root directory. This will be used to store all the container build information and will make it easier for us to build and run the containers.

Here is the docker-compose file we have added the configuration for –

php – for PHP processing by PHP FPM
nginx – to serve the processed output from PHP FPM and handle other HTTP requests
mysql – as a database service
node – for UI field processing, using vite
# docker-compose.yml

services:
    php:
        build:
            context: .
            dockerfile: ./docker/php/php.Dockerfile
        container_name: bigboxcode-php
        restart: unless-stopped
        working_dir: /var/www
        volumes:
            - ./:/var/www
            - ./.env:/var/www/.env
            - /var/www/vendor
        environment:
            - APP_ENV=development
        networks:
            - bigboxcode-network
        depends_on:
            - mysql

    nginx:
        image: nginx:alpine
        container_name: bigboxcode-nginx
        ports:
            - 8000:80
        volumes:
            - ./:/var/www
            - ./docker/nginx/log:/var/log/nginx
            - ./docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
        depends_on:
            - php
            - mysql
        networks:
            - bigboxcode-network

    mysql:
        image: mysql:8.0
        container_name: bigboxcode-mysql
        ports:
            - 3306:3306
        volumes:
            - mysql_data:/var/lib/mysql
        environment:
            MYSQL_DATABASE: bigboxcode
            MYSQL_ROOT_PASSWORD: root
            MYSQL_PASSWORD: bigboxpass
            MYSQL_USER: bigboxuser
        networks:
            - bigboxcode-network

    node:
        # platform: linux/arm64/v8 #this line is optional if you are using Mac Silicon chip (M1/M2/M3)
        build:
            context: .
            dockerfile: ./docker/node/node.Dockerfile
        container_name: bigboxcode-node
        ports:
            - 5173:5173
        restart: unless-stopped
        working_dir: /var/www
        volumes:
            - ./:/var/www
            - /var/www/node_modules
        environment:
            - NODE_ENV=development
            # - CHOKIDAR_USEPOLLING=true # required for file change reflection
            # - CHOKIDAR_INTERVAL=3000
        networks:
            - bigboxcode-network
        depends_on:
            - php

volumes:
    "mysql_data":


networks:
    "bigboxcode-network":
        driver: bridge

Run Application

Run the following command to start the containers-

docker compose up

# Or you can run the following if the above command does not work in your case
# docker-compose up
Bash

The above command will pull the required images, and then build and run the containers.

If you check your docker desktop “container” list then you will see the following containers running.

Dockerize Laravel Application
Dockerize Laravel Application

NOTE

Use the same command “docker compose up” to run the application every time you want to start the container.

Makefile (optional)

Additionally, to make this easy and so that you don’t have to memorize the above commands, you can use the following Makefile.

# Makefile

PHP_CONTAINER = bigboxcode-php
NODE_CONTAINER = bigboxcode-node

# Run the application
default:
	docker compose up

# Build docker containers and prepare the environment
build:
	docker compose build --no-cache --progress=plain

# Access PHP container
access-php:
	docker exec -it $(PHP_CONTAINER) sh

# Run migration in the PHP container
migrate:
	docker exec -it $(PHP_CONTAINER) php artisan migrate

# Sync vendor directory from PHP container to the host
vendor-sync:
	docker cp $(PHP_CONTAINER):/var/www/vendor ./
	
# Sync node_modules directory from node container to the host
node-modules-sync:
	docker cp $(NODE_CONTAINER):/var/www/node_modules ./

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.