Dockerize Laravel: Nginx, MariaDB, PhpMyAdmin Setup
Developing Laravel applications often requires a consistent and reproducible environment. This article outlines how to set up a Dockerized development environment for a Laravel application, incorporating Nginx, MariaDB, and phpMyAdmin. This setup ensures that developers have a standardized stack, reducing environment drift and setup friction across different machines.
Introduction to Dockerizing Laravel Applications
Dockerizing your Laravel application offers numerous advantages. By encapsulating your application and its dependencies into containers, you ensure consistency across development, testing, and production environments. This approach eliminates the common āit works on my machineā problem and streamlines the deployment process. Using Docker, you can easily manage different versions of PHP, databases, and other services without conflicts. In this comprehensive guide, we'll walk you through setting up a complete Dockerized environment for your Laravel application, including Nginx, MariaDB, and phpMyAdmin. We will cover everything from configuring the docker-compose.yml file to setting up web server routing and optimizing the PHP environment. Additionally, we'll provide detailed documentation to help you get started, manage your daily workflow, and troubleshoot common issues. This setup not only simplifies development but also enhances collaboration among team members by providing a unified and reproducible development environment. By the end of this guide, you'll have a robust Dockerized environment that supports larger PHP memory and upload limits, preventing common development-time errors and ensuring a smooth development experience.
Prerequisites
Before diving into the setup, ensure you have the following prerequisites installed:
- Docker: Install Docker Desktop from the official Docker website.
- Docker Compose: Docker Compose is usually included with Docker Desktop. Verify the installation by running
docker-compose versionin your terminal.
Dockerized Stack Setup: docker-compose.yml Configuration
The core of our Dockerized environment lies in the docker-compose.yml file. This file defines the services needed for our Laravel application: app (PHP-FPM 8.3), web (Nginx), db (MariaDB 10.5), and optionally phpmyadmin.
Configuring the docker-compose.yml File
To begin, create a new file named docker-compose.yml in the root directory of your Laravel project. This file will define the services that make up your development environment. Hereās a detailed breakdown of how to configure each service:
1. App (PHP-FPM 8.3)
The app service will run PHP-FPM 8.3 and serve as the application container. It's responsible for executing PHP code and handling requests passed from the web server (Nginx). Define the app service in your docker-compose.yml as follows:
version: "3.8"
services:
app:
build:
context: .
dockerfile: docker/app/Dockerfile
container_name: app
working_dir: /var/www/
volumes:
- ./:/var/www
ports:
- "9000:9000"
depends_on:
- db
environment:
PHP_IDE_CONFIG: "serverName=Docker"
XDEBUG_MODE: debug
XDEBUG_CONFIG: "client_host=host.docker.internal client_port=9003"
Explanation:
build: Specifies the build context and Dockerfile used to build the image. The context is set to the current directory (.), and the Dockerfile is located atdocker/app/Dockerfile.container_name: Assigns the nameappto the container, making it easier to reference.working_dir: Sets the working directory inside the container to/var/www/, which is where your Laravel application code will reside.volumes: Mounts the project source code into the container. The./:/var/wwwmapping ensures that any changes made to the code on your host machine are immediately reflected in the container.ports: Exposes port 9000 on the container, which is the default port for PHP-FPM.depends_on: Ensures that thedbservice is started before theappservice.environment: Sets environment variables for PHP, including configuration for Xdebug, which is used for debugging.
2. Web (Nginx)
The web service uses Nginx to serve the Laravel application. It routes HTTP requests to the app service for PHP processing. Define the web service as follows:
web:
build:
context: .
dockerfile: docker/web/Dockerfile
container_name: web
ports:
- "8000:80"
volumes:
- ./:/var/www
- ./docker/web/nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
Explanation:
build: Similar to theappservice, this specifies the build context and Dockerfile for the Nginx image.container_name: Assigns the namewebto the container.ports: Maps port 8000 on your host machine to port 80 on the container, allowing you to access the application viahttp://localhost:8000.volumes: Mounts the project source code and the Nginx configuration file into the container.depends_on: Ensures that theappservice is running before starting Nginx.
3. DB (MariaDB 10.5)
The db service runs MariaDB 10.5 and provides the database for your Laravel application. Define the db service as follows:
db:
image: mariadb:10.5
container_name: db
ports:
- "3306:3306"
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: laravel
MYSQL_USER: laravel
MYSQL_PASSWORD: laravel
Explanation:
image: Specifies the MariaDB 10.5 image from Docker Hub.container_name: Assigns the namedbto the container.ports: Maps port 3306 on your host machine to port 3306 on the container, allowing you to connect to the database using a client like phpMyAdmin or a database management tool.volumes: Creates a named volumedb_datato persist the database data across container restarts. This ensures that your data is not lost when the container is stopped or removed.environment: Sets environment variables for the MariaDB instance, including the root password, database name, user, and password.
4. phpMyAdmin (Optional)
The phpmyadmin service provides a web interface for managing your MariaDB database. This is an optional but highly convenient service for development. Define the phpmyadmin service as follows:
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: phpmyadmin
ports:
- "8080:80"
environment:
PMA_HOST: db
PMA_PORT: 3306
depends_on:
- db
Explanation:
image: Specifies the phpMyAdmin image from Docker Hub.container_name: Assigns the namephpmyadminto the container.ports: Maps port 8080 on your host machine to port 80 on the container, allowing you to access phpMyAdmin viahttp://localhost:8080.environment: Sets environment variables for phpMyAdmin, including the host and port of the MariaDB database.depends_on: Ensures that thedbservice is running before starting phpMyAdmin.
Complete docker-compose.yml File
Here is the complete docker-compose.yml file for your reference:
version: "3.8"
services:
app:
build:
context: .
dockerfile: docker/app/Dockerfile
container_name: app
working_dir: /var/www/
volumes:
- ./:/var/www
ports:
- "9000:9000"
depends_on:
- db
environment:
PHP_IDE_CONFIG: "serverName=Docker"
XDEBUG_MODE: debug
XDEBUG_CONFIG: "client_host=host.docker.internal client_port=9003"
web:
build:
context: .
dockerfile: docker/web/Dockerfile
container_name: web
ports:
- "8000:80"
volumes:
- ./:/var/www
- ./docker/web/nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
db:
image: mariadb:10.5
container_name: db
ports:
- "3306:3306"
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: laravel
MYSQL_USER: laravel
MYSQL_PASSWORD: laravel
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: phpmyadmin
ports:
- "8080:80"
environment:
PMA_HOST: db
PMA_PORT: 3306
depends_on:
- db
volumes:
db_data:
Web Server Routing: Nginx Configuration
Nginx needs to be configured to serve the Laravel application from the public directory and route PHP requests to the app container on port 9000. This is achieved through a custom Nginx configuration file.
Setting Up Nginx Configuration
Create a directory named docker/web in the root of your Laravel project. Inside this directory, create a file named nginx.conf with the following content:
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;
}
}
Explanation:
listen 80: Listens for HTTP requests on port 80.index index.php index.html: Specifies the default index files.root /var/www/public: Sets the root directory to thepublicfolder of your Laravel application.location ~ \.php$: Configures how Nginx handles PHP files. It passes PHP requests to theappservice on port 9000 using FastCGI.try_files $uri $uri/ /index.php?$query_string: Attempts to serve static files first. If a file or directory is not found, it passes the request toindex.php.
PHP Environment Tuning
To avoid common development-time errors, itās essential to set appropriate PHP memory and upload limits. This can be done by creating a custom PHP configuration file.
Creating a Custom PHP Configuration
Create a directory named docker/app in the root of your Laravel project. Inside this directory, create a file named Dockerfile with the following content:
FROM php:8.3-fpm
# Copy composer.lock and composer.json
COPY composer.lock composer.json /var/www/
# Set working directory
WORKDIR /var/www
# Install dependencies
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
# 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
# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Add user for laravel application
RUN groupadd -g 1000 www
RUN useradd -u 1000 -ms /bin/bash www -g www
# Copy existing application source code
COPY . /var/www
# Change current user to www
USER www
# Run composer install
RUN composer install --ignore-platform-reqs
# Copy entrypoint.sh
COPY docker/app/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
EXPOSE 9000
CMD ["php-fpm"]
Next, create a file named entrypoint.sh inside the same docker/app directory with the following content:
#!/bin/sh
# Set PHP memory limit
echo "memory_limit = 256M" > /usr/local/etc/php/conf.d/custom.ini
# Set PHP upload limit
echo "upload_max_filesize = 32M" >> /usr/local/etc/php/conf.d/custom.ini
echo "post_max_size = 32M" >> /usr/local/etc/php/conf.d/custom.ini
# Execute PHP-FPM
exec "$@"
Make sure to give execute permissions to the entrypoint.sh file:
chmod +x docker/app/entrypoint.sh
Explanation:
- The
Dockerfileextends thephp:8.3-fpmimage and installs necessary PHP extensions and tools. - The
entrypoint.shscript sets the PHPmemory_limit,upload_max_filesize, andpost_max_sizein a custom.inifile. This ensures that PHP has enough memory and can handle larger file uploads.
Developer Documentation: docker-compose.md
Providing clear documentation is crucial for developers to quickly understand and use the Dockerized environment. Create a docker-compose.md file in the root of your project with the following sections:
Prerequisites
- Docker: Ensure Docker Desktop is installed.
- Docker Compose: Verify Docker Compose is installed.
Setup Steps
- Clone the repository.
- Navigate to the project directory:
cd your-project. - Run
docker-compose up -dto build and start the containers. - Run
docker exec -it app composer installto install PHP dependencies. - Generate the application key:
docker exec -it app php artisan key:generate. - Set up the database:
docker exec -it app php artisan migrate.
Daily Usage
- Start the containers:
docker-compose up -d. - Stop the containers:
docker-compose down. - Access the application:
http://localhost:8000. - Access phpMyAdmin (if installed):
http://localhost:8080.
Useful Commands
- Enter the
appcontainer:docker exec -it app bash. - Run Artisan commands:
docker exec -it app php artisan <command>. - View container logs:
docker-compose logs -f <service>(e.g.,docker-compose logs -f app).
Troubleshooting
- Issue: Application not accessible.
- Solution: Ensure Docker containers are running and ports are correctly mapped.
- Issue: Database connection errors.
- Solution: Verify database credentials and that the
dbcontainer is running.
- Solution: Verify database credentials and that the
- Issue: Composer errors.
- Solution: Ensure Composer is installed and run
composer installinside theappcontainer.
- Solution: Ensure Composer is installed and run
Source Mounting and Persistence
Source mounting is configured in the docker-compose.yml file using volumes. This allows changes to the project source code on the host machine to be immediately reflected in the containers.
Configuring Volumes
The following lines in the docker-compose.yml file ensure source mounting:
volumes:
- ./:/var/www
This mounts the current directory (.) on the host machine to the /var/www directory in the app and web containers. Database data persistence is achieved using a named volume:
volumes:
db_data:/var/lib/mysql
This creates a named volume db_data that persists the MariaDB data across container restarts.
Conclusion
Setting up a Dockerized development environment for Laravel applications with Nginx, MariaDB, and phpMyAdmin ensures consistency, reproducibility, and ease of use. This setup reduces environment drift, simplifies setup friction, and provides a standardized stack for all developers. By following this guide, you can create a robust and efficient development environment for your Laravel projects.
For more information on Docker and its best practices, visit the official Docker documentation. Happy coding!