DEV Community

Cover image for Creating a simple environment with Docker, PHP 8.4, Composer, Nginx, and MariaDB.
Wellisson Ribeiro
Wellisson Ribeiro

Posted on

Creating a simple environment with Docker, PHP 8.4, Composer, Nginx, and MariaDB.

This is my first article on this platform, and the goal here is to keep things simple, practical, and easy to follow.

You've probably had trouble installing PHP extensions, configuring Nginx, or installing a database on your local machine, just like me; Docker can make your life much easier. In this guide, we will build a modern and simple development environment using:

  • PHP 8.4 (FPM)
  • Composer
  • Nginx
  • MariaDB
  • Docker and Docker Compose

All services will run together with a single command.


Project structure

Start by creating the following folder structure:

root-folder/
├── docker/
│   ├── nginx/
│   │   └── default.conf
│   └── php/
│       └── Dockerfile
├── src/
│   └── index.php
├── docker-compose.yml
└── composer.json
Enter fullscreen mode Exit fullscreen mode

Each folder has a clear responsibility:

  • docker/php: PHP image and extensions
  • docker/nginx: Nginx configuration
  • src: application source code

PHP 8.4 with Composer (Dockerfile)

Create the file docker/php/Dockerfile:

# Base image with PHP 8.4 and FPM
FROM php:8.4-fpm

# Install system dependencies and PHP extensions
RUN apt-get update && apt-get install -y \
    git \
    unzip \
    libzip-dev \
    && docker-php-ext-install pdo pdo_mysql zip

# Install Composer from the official image
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

# Set the working directory
WORKDIR /var/www/html
Enter fullscreen mode Exit fullscreen mode

What this Dockerfile does

  • Uses PHP 8.4 FPM, ideal for Nginx
  • Installs common system tools (git, unzip)
  • Enables essential PHP extensions for database and zip handling
  • Adds Composer without manual installation

Simple Nginx configuration

Create the file docker/nginx/default.conf:

server {
    listen 80;
    index index.php index.html;
    root /var/www/html;

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

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}
Enter fullscreen mode Exit fullscreen mode

What this configuration does

  • Listens on port 80
  • Serves files from /var/www/html
  • Forwards .php requests to the PHP container via FastCGI

This setup is minimal but works well for APIs and simple PHP applications.


Docker Compose (the core of the setup)

Create the file docker-compose.yml in the project root:

version: '3.9'

services:
  php:
    build: ./docker/php
    container_name: php84
    volumes:
      - ./src:/var/www/html
    depends_on:
      - mariadb

  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - "8080:80"
    volumes:
      - ./src:/var/www/html
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php

  mariadb:
    image: mariadb:11
    container_name: mariadb
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: app
      MYSQL_USER: app
      MYSQL_PASSWORD: app
    ports:
      - "3306:3306"
    volumes:
      - mariadb_data:/var/lib/mysql

volumes:
  mariadb_data:
Enter fullscreen mode Exit fullscreen mode

What this docker-compose.yml does

This file defines and connects all services needed for the development environment.

version

version: '3.9'
Enter fullscreen mode Exit fullscreen mode

Defines the Docker Compose file format version. Version 3.9 is stable and widely supported.


php service

php:
  build: ./docker/php
  container_name: php84
  volumes:
    - ./src:/var/www/html
  depends_on:
    - mariadb
Enter fullscreen mode Exit fullscreen mode
  • Builds a custom PHP image using the Dockerfile inside docker/php
  • Mounts the local src folder into the container so changes are reflected instantly
  • Depends on MariaDB, ensuring the database container starts first

nginx service

nginx:
  image: nginx:latest
  container_name: nginx
  ports:
    - "8080:80"
  volumes:
    - ./src:/var/www/html
    - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
  depends_on:
    - php
Enter fullscreen mode Exit fullscreen mode
  • Uses the official Nginx image
  • Maps port 8080 on your machine to port 80 inside the container
  • Shares the same application code with PHP
  • Loads the custom Nginx configuration file
  • Depends on the PHP container to handle .php requests

mariadb service

mariadb:
  image: mariadb:11
  container_name: mariadb
  environment:
    MYSQL_ROOT_PASSWORD: root
    MYSQL_DATABASE: app
    MYSQL_USER: app
    MYSQL_PASSWORD: app
  ports:
    - "3306:3306"
  volumes:
    - mariadb_data:/var/lib/mysql
Enter fullscreen mode Exit fullscreen mode
  • Runs MariaDB version 11
  • Automatically creates a database and user on startup
  • Exposes port 3306 for local connections (optional for development)
  • Stores database data in a named volume

Volumes

volumes:
  mariadb_data:
Enter fullscreen mode Exit fullscreen mode

This named volume persists database data even if containers are stopped or recreated.


Services overview

  • php: runs PHP 8.4 with Composer
  • nginx: handles HTTP requests
  • mariadb: provides a persistent database

The mariadb_data volume ensures that database data is not lost when containers stop.


PHP test file (with database connection)

Create the file src/index.php:

<?php

$host = 'mariadb';
$db = 'app';
$user = 'app';
$pass = 'app';
$charset = 'utf8mb4';
$port = 3306;

$dsn = "mysql:host={$host};port={$port};dbname={$db};charset={$charset}";

try {
    $pdo = new PDO(
        $dsn, 
        $user, 
        $pass, 
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]
    );

    echo "PHP is running and connected to MariaDB successfully!";
} catch (PDOException $e) {
    echo "Database connection failed: {$e->getMessage()}";
}
Enter fullscreen mode Exit fullscreen mode

What this test file does

  • Uses PDO, the recommended way to connect to databases in PHP
  • Connects to MariaDB using the service name mariadb as the host
  • Reuses the same credentials defined in docker-compose.yml
  • Prints a success message if the connection works
  • Displays an error message if something goes wrong

If you see the success message in the browser, it means PHP, Nginx, and MariaDB are communicating correctly.


Composer configuration

Create the file composer.json:

{
  "name": "example/docker-php",
  "require": {}
}
Enter fullscreen mode Exit fullscreen mode

To run Composer inside the PHP container:

docker compose run --rm php composer install
Enter fullscreen mode Exit fullscreen mode

This command uses the same PHP environment defined in Docker, avoiding local PHP version issues.


Running the environment

From the project root, run:

docker compose up -d --build
Enter fullscreen mode Exit fullscreen mode

Then open your browser:

http://localhost:8080

If everything is working, you should see:

PHP is running and connected to MariaDB successfully!
Enter fullscreen mode Exit fullscreen mode

Conclusion

With this setup you get:

  • PHP 8.4 ready for development
  • Composer fully integrated
  • Nginx as a lightweight web server
  • MariaDB with persistent data
  • A clean and isolated development environment

This is a solid starting point for plain PHP projects and APIs.

That's all for today, folks!

Top comments (1)

Collapse
 
leojoaodev profile image
Leo

Very good, I'll use it on my next project