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.
Purpose | Dockerfile | Config file | |
---|---|---|---|
PHP FPM | php.Dockerfile | php.ini | docker/php/php.Dockerfile docker/php/php.ini |
Nginx | nginx.conf | docker/nginx/nginx.conf | |
NodeJS(for UI using Vite) | node.Dockerfile | docker/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-
# 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
ININOTE
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
DockerfileNginx 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-
# 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-
# 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 –
# 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
BashThe 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.
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 ./