🚨 ¡Nueva review! ✨ Mi ratón favorito para programar: el Logitech MX Master 3S . ¡Échale un ojo! 👀

Creando un simple entorno con Docker

PHP 8.4, Nginx, MariaDB y Composer sin ensuciar tu máquina

Escrito por domin el 22 de febrero de 2026

Introducción

Seeeeeeeeeeeeguro que has tenido problemas instalando versiones de php, extensiones de php, configurando nginx o apache, instalado bases de datos o usando alguna en local…en fin! Que como ya a estas alturas sabrás, cuando se trata de desarrollar, lo que lo peta es poder levantar un entorno virtual con todas las versiones que tocan y todas las dependencias que tocan y olvidarse del resto. Por eso, vamos a intentar hacer un Skeleton para ello, porque Docker puede hacerte la vida mucho más fácil!

Entorno de desarrollo con Docker, PHP, Nginx y MariaDB.

En este caso vamos a ver de intentar implementar un entorno en Docker que tenga:

Y para ello vamos a usar Docker y .

¿Qué son Docker y Docker Compose? ¿No son lo mismo? ¿En qué se diferencian? Pues Docker es la tecnología base de gestión de contenedores virtuales y Docker Compose es el orquestador.


Estructura de ficheros

Para comenzar a hacer nuestro skeleton vamos a definir la estructura de ficheros que vamos a tener.

php-docker-skeleton/
├── docker/
   ├── nginx/
   └── default.conf          # Configuración del servidor Nginx
   └── php/
       └── Dockerfile            # Imagen PHP 8.4-FPM con extensiones y Composer
├── src/
   └── index.php                 # Punto de entrada de la aplicación
├── .gitignore                    # Exclusiones de ficheros para el repositorio Git
├── composer.json                 # Dependencias PHP del proyecto
└── docker-compose.yml            # Orquestación de servicios Docker

En el directorio /docker/nginx vamos a tener la config de nginx y en el de /docker/php vamos a tener la imagen de php y las extensiones. En /src vamos a tener el código fuente que vamos a querer mostrar, es decir, vamos a poner aquí el punto de entrada. Si fuera por ejemplo una app Symfony, esto sería el símil a public/index.php

Imagen de php en Docker con Dockerfile

es un fichero de texto simple sin extensión que contiene una serie de instrucciones paso a paso para crear la imagen de Docker. Estas instrucciones son comandos, por ejemplo para descargar una imagen de Docker, crear directorios y ficheros, descargar por ejemplo Composer etc. Lo necesitamos en el proyecto porque a diferencia de nginx o MariaDB que se descargan tal cual y no necesitan modificaciones, php necesita Dockerfile para por ejemplo instalar las extensiones.

Nuestro fichero Dockerfile ahora pinta así:

FROM php:8.4-fpm

# Instalar extensiones comunes
RUN apt-get update && apt-get install -y \
    git \
    unzip \
    libzip-dev \
    && docker-php-ext-install pdo pdo_mysql zip

COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

WORKDIR /var/www/html

En la primera línea que vemos FROM php:8.4-fpm le estamos definiendo una imagen base ya hecha con la versión php 8.4 con . FPM es FastCGI Process Manager que sirve para ejecutar aplicaciones web junto a algún servidor tipo apache o nginx. Con RUN.. apt patatas le estamos diciendo primero que actualice los repositorios e instalar dependencias necesarias del sistema y con docker-php-ext-install etc utilizamos un fichero nativo de la imagen para instalar extensiones de php. El resto como puedes ir deduciendo son comandos de sistema para ir creando el entorno perfecto. Copiar Composer, establecer el directorio de trabajo con WORKDIR etc.

Configuración de nginx

Seguimos con la configuración para el servidor nginx:

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;
    }
}

En esta configuración, definimos que:

Fichero docker-compose.yaml

Aquí está todo el tinglado, vamos a verlo:

services:
  # Servidor Web (Nginx)
  nginx:
    image: nginx:latest
    container_name: php-skeleton-nginx
    ports:
      - "8080:80"
    volumes:
      - ./src:/var/www/html
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php

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

  # Base de Datos
  mariadb:
    image: mariadb:11
    container_name: php-skeleton-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:

En este entorno hemos decidido montar un servidor web nginx con un intérprete de php y una base de datos mariadb. Por ejemplo vamos a comenzar viendo con detalle el primer tramo, el del servidor web:

Servidor nginx

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

Servidor php

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

y finalmente la base de datos

Base de datos

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

Test!

Ahora para probarlo todo bien vamos a hacer un fichero php con una prueba de conexión a base de datos y lo vamos a guardar en src/index.php. Usaremos para la conexión.

<?php

function connectToDatabase(): PDO
{
    $host = 'mariadb';
    $port = 3306;
    $db = 'app';
    $user = 'app';
    $pass ='app';
    $charset = 'utf8mb4';

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

    $options = [
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES   => false,
    ];

    return new PDO($dsn, $user, $pass, $options);
}

try {
    $pdo = connectToDatabase();
    echo "PHP funciona y estás conectado a la base de datos";

} catch (PDOException $e) {
    echo "Fallo en la conexión a la base de datos: " . $e->getMessage();
}

También crearemos nuestro fichero composer.json.

{
  "name": "ejemplo/php-docker-skeleton",
  "require": {
    "ext-pdo": "*"
  }
}

Y para ejecutarlo dentro del contenedor haríamos lo siguiente:

docker compose run --rm php composer install

Con esto nos aseguramos de usar el entorno de php definido en docker, evitando ejecutar nada con versiones de php locales.

Levantar el contenedor

Para levantar el contenedor basta con:

docker compose up -d --build

Y luego ir al navegador y entrar a: http://localhost:8080

Aquí deberías ver el texto del mensaje que hemos configurado antes en el fichero index.php.

Y EA eso es todo, más adelante veremos cómo crear un docker para NEST JS.

Saluditos y nos beermos! 🍻