Crear un entorno DEV tipo XAMPP/MAMP con Docker

Objetivo del proyecto

En esta práctica vamos a crear un entorno de desarrollo web usando Docker. El objetivo es tener un sistema parecido a XAMPP o MAMP, pero más profesional, portable y fácil de reconstruir.

El entorno permitirá trabajar con:

  • Apache
  • PHP
  • Extensiones comunes de PHP
  • MySQL
  • phpMyAdmin
  • Mailpit para probar correos
  • Redis como servicio adicional opcional
  • Una carpeta local donde guardaremos todos nuestros proyectos web

Todos los contenedores tendrán el prefijo:

DEV_

De esta forma podremos identificarlos fácilmente dentro de Docker.


1. ¿Qué vamos a construir?

El sistema tendrá esta estructura:

Carpeta local del alumno


+-----------------------------+
| Carpeta DEVLOCAL |
| |
| proyecto1/ |
| proyecto2/ |
| pruebas/ |
| _docker/ |
+-------------+---------------+


+-----------------------------+
| Docker Compose |
+-------------+---------------+


+-----------------------------+
| DEV_apache_php |
| DEV_mysql |
| DEV_phpmyadmin |
| DEV_mailpit |
| DEV_redis |
+-----------------------------+

El alumno podrá crear una carpeta con un proyecto PHP y verlo desde el navegador.

Por ejemplo:

http://localhost:8080/pruebas/

2. Requisitos previos

Cada alumno necesitará:

  • Un ordenador con Windows, Ubuntu o macOS.
  • Docker instalado.
  • Un editor de código, por ejemplo VS Code.
  • Terminal o consola.
  • Navegador web.

Docker Compose se usará para definir y levantar varios contenedores a la vez. Docker lo describe como una herramienta para definir y ejecutar aplicaciones multicontenedor.


3. Instalación de Docker en Windows

En Windows se recomienda usar Docker Desktop.

Docker Desktop para Windows incluye Docker Engine, Docker CLI y Docker Compose. La documentación oficial indica que Docker Desktop puede usar WSL 2 como motor de ejecución en Windows.

Pasos recomendados

  1. Instalar o activar WSL 2.
  2. Instalar Docker Desktop para Windows.
  3. Reiniciar el equipo si lo solicita.
  4. Abrir Docker Desktop.
  5. Comprobar que Docker está funcionando.

Desde PowerShell o Terminal de Windows:

docker --version
docker compose version

Si ambos comandos responden con una versión, Docker está funcionando correctamente.

Carpeta recomendada en Windows

Para evitar problemas con permisos o sincronización, se recomienda crear la carpeta directamente en C:\.

mkdir C:\DEVLOCAL

No es recomendable usar carpetas dentro de OneDrive para este tipo de práctica.


4. Instalación de Docker en Ubuntu

En Ubuntu se puede instalar Docker Engine directamente desde los repositorios oficiales de Docker. La documentación oficial recomienda configurar primero el repositorio apt de Docker y después instalar Docker Engine y sus plugins.

Actualizar paquetes

sudo apt update
sudo apt upgrade -y

Instalar dependencias

sudo apt install -y ca-certificates curl gnupg

Crear carpeta para claves

sudo install -m 0755 -d /etc/apt/keyrings

Descargar clave oficial de Docker

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

Dar permisos a la clave

sudo chmod a+r /etc/apt/keyrings/docker.gpg

Añadir repositorio oficial

echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Instalar Docker

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Comprobar instalación

docker --version
docker compose version

Permitir usar Docker sin sudo

sudo usermod -aG docker $USER

Después de este comando, el alumno debe cerrar sesión y volver a entrar.

Carpeta recomendada en Ubuntu

mkdir -p ~/DEVLOCAL

5. Instalación de Docker en macOS

En macOS se recomienda instalar Docker Desktop para Mac. La documentación oficial diferencia entre Mac con chip Intel y Mac con Apple Silicon, por lo que hay que descargar la versión adecuada.

Pasos recomendados

  1. Descargar Docker Desktop para Mac.
  2. Elegir la versión correcta:
    • Mac Intel.
    • Mac Apple Silicon.
  3. Instalar la aplicación.
  4. Abrir Docker Desktop.
  5. Esperar a que Docker arranque completamente.
  6. Comprobar desde Terminal:
docker --version
docker compose version

Carpeta recomendada en macOS

En el caso de este ejemplo usaremos:

/Users/antoniooteroveiga/DEVLOCAL

Para otro usuario sería algo similar a:

/Users/nombre_usuario/DEVLOCAL

6. Crear la estructura del proyecto

La estructura será la misma en Windows, Ubuntu y macOS.

Windows

Desde PowerShell:

mkdir C:\DEVLOCAL
mkdir C:\DEVLOCAL\_docker
mkdir C:\DEVLOCAL\_docker\php
mkdir C:\DEVLOCAL\_docker\apache
mkdir C:\DEVLOCAL\pruebas

Ubuntu

Desde Terminal:

mkdir -p ~/DEVLOCAL/_docker/php
mkdir -p ~/DEVLOCAL/_docker/apache
mkdir -p ~/DEVLOCAL/pruebas

macOS

Desde Terminal:

mkdir -p /Users/antoniooteroveiga/DEVLOCAL/_docker/php
mkdir -p /Users/antoniooteroveiga/DEVLOCAL/_docker/apache
mkdir -p /Users/antoniooteroveiga/DEVLOCAL/pruebas

La estructura final será:

DEVLOCAL/
├── _docker/
│ ├── docker-compose.yml
│ ├── inicio.sh
│ ├── inicio.bat
│ ├── php/
│ │ ├── Dockerfile
│ │ ├── php.ini
│ │ └── msmtprc
│ └── apache/
│ └── 000-default.conf
└── pruebas/
└── index.php

7. Crear el archivo docker-compose.yml

Este archivo define todos los servicios del entorno.

Debe estar dentro de:

DEVLOCAL/_docker/docker-compose.yml

Contenido:

services:

apache_php:
build:
context: .
dockerfile: php/Dockerfile
container_name: DEV_apache_php
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ../:/var/www/html
- ./apache/000-default.conf:/etc/apache2/sites-available/000-default.conf
- ./php/php.ini:/usr/local/etc/php/conf.d/dev-custom.ini
- ./php/msmtprc:/etc/msmtprc
depends_on:
- mysql
- mailpit
networks:
- DEV_network

mysql:
image: mysql:8.4
container_name: DEV_mysql
restart: unless-stopped
ports:
- "3307:3306"
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: devdb
MYSQL_USER: devuser
MYSQL_PASSWORD: devpass
volumes:
- DEV_mysql_data:/var/lib/mysql
networks:
- DEV_network

phpmyadmin:
image: phpmyadmin:latest
container_name: DEV_phpmyadmin
restart: unless-stopped
ports:
- "8081:80"
environment:
PMA_HOST: mysql
PMA_PORT: 3306
PMA_USER: root
PMA_PASSWORD: root
UPLOAD_LIMIT: 256M
depends_on:
- mysql
networks:
- DEV_network

mailpit:
image: axllent/mailpit:latest
container_name: DEV_mailpit
restart: unless-stopped
ports:
- "8025:8025"
- "1025:1025"
networks:
- DEV_network

redis:
image: redis:latest
container_name: DEV_redis
restart: unless-stopped
ports:
- "6379:6379"
networks:
- DEV_network

volumes:
DEV_mysql_data:

networks:
DEV_network:
name: DEV_network

8. Crear el archivo Dockerfile

Este archivo construirá nuestro contenedor de Apache con PHP.

Debe estar en:

DEVLOCAL/_docker/php/Dockerfile

Contenido:

FROM php:8.3-apache

RUN apt-get update && apt-get install -y \
git \
unzip \
zip \
curl \
msmtp \
msmtp-mta \
libzip-dev \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
libicu-dev \
libonig-dev \
libxml2-dev \
libssl-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install \
mysqli \
pdo \
pdo_mysql \
zip \
gd \
intl \
mbstring \
bcmath \
soap \
opcache \
&& a2enmod rewrite headers expires \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

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

WORKDIR /var/www/html

Con esto tendremos disponibles muchas extensiones habituales de PHP:

  • mysqli
  • pdo_mysql
  • gd
  • zip
  • intl
  • mbstring
  • bcmath
  • soap
  • opcache

También tendremos instalado Composer, muy útil para proyectos PHP modernos.


9. Crear el archivo php.ini

Debe estar en:

DEVLOCAL/_docker/php/php.ini

Contenido:

display_errors = On
display_startup_errors = On
error_reporting = E_ALL

upload_max_filesize = 256M
post_max_size = 256M
memory_limit = 512M
max_execution_time = 300
max_input_vars = 5000

date.timezone = Europe/Madrid

opcache.enable = 1
opcache.enable_cli = 1

sendmail_path = "/usr/bin/msmtp -t"

Este archivo ajusta PHP para un entorno de desarrollo.

No es una configuración pensada para producción. En producción no deberíamos mostrar errores directamente al usuario.


10. Crear el archivo msmtprc

Este archivo permitirá enviar correos desde PHP hacia Mailpit.

Debe estar en:

DEVLOCAL/_docker/php/msmtprc

Contenido:

defaults
auth off
tls off

account mailpit
host mailpit
port 1025
from devlocal@example.test

account default : mailpit

Mailpit capturará los correos y podremos verlos desde el navegador.


11. Crear la configuración de Apache

Debe estar en:

DEVLOCAL/_docker/apache/000-default.conf

Contenido:

<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html

<Directory /var/www/html>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>

ErrorLog ${APACHE_LOG_DIR}/dev_error.log
CustomLog ${APACHE_LOG_DIR}/dev_access.log combined
</VirtualHost>

La directiva importante es:

AllowOverride All

Esto permite usar archivos .htaccess, necesarios en muchos proyectos PHP, como WordPress, Laravel o aplicaciones con URLs amigables.


12. Crear una página de prueba

Creamos el archivo:

DEVLOCAL/pruebas/index.php

Contenido:

<?php

echo "<h1>Entorno DEV funcionando</h1>";
echo "<p>Apache y PHP están funcionando correctamente.</p>";

echo "<h2>Información de PHP</h2>";
phpinfo();

13. Levantar el entorno manualmente

Windows

Desde PowerShell:

cd C:\DEVLOCAL\_docker
docker compose up -d --build

Ubuntu

Desde Terminal:

cd ~/DEVLOCAL/_docker
docker compose up -d --build

macOS

Desde Terminal:

cd /Users/antoniooteroveiga/DEVLOCAL/_docker
docker compose up -d --build

14. Comprobar los contenedores

Ejecutamos:

docker ps

Deberíamos ver contenedores parecidos a estos:

DEV_apache_php
DEV_mysql
DEV_phpmyadmin
DEV_mailpit
DEV_redis

15. Acceder al entorno desde el navegador

Apache + PHP

http://localhost:8080

Proyecto de pruebas

http://localhost:8080/pruebas/

phpMyAdmin

http://localhost:8081

Datos de acceso:

Servidor: mysql
Usuario: root
Contraseña: root

También podemos usar:

Servidor: mysql
Usuario: devuser
Contraseña: devpass

Mailpit

http://localhost:8025

MySQL desde el equipo anfitrión

Para conectarse desde DBeaver, DataGrip, VS Code o MySQL Workbench:

Host: localhost
Puerto: 3307
Usuario: devuser
Contraseña: devpass
Base de datos: devdb

MySQL desde PHP

Desde código PHP, el host no será localhost, sino el nombre del servicio Docker:

Host: mysql
Puerto: 3306
Usuario: devuser
Contraseña: devpass
Base de datos: devdb

16. Probar conexión con MySQL desde PHP

Creamos el archivo:

DEVLOCAL/pruebas/mysql.php

Contenido:

<?php

$host = "mysql";
$db = "devdb";
$user = "devuser";
$pass = "devpass";

$conexion = new mysqli($host, $user, $pass, $db);

if ($conexion->connect_error) {
die("Error de conexión: " . $conexion->connect_error);
}

echo "<h1>Conexión correcta con MySQL</h1>";
echo "<p>La base de datos devdb está disponible.</p>";

$conexion->close();

Abrimos en el navegador:

http://localhost:8080/pruebas/mysql.php

Si todo está correcto, veremos un mensaje confirmando la conexión.


17. Probar envío de correo con Mailpit

Creamos el archivo:

DEVLOCAL/pruebas/mail.php

Contenido:

<?php

$destino = "alumno@example.test";
$asunto = "Prueba desde PHP";
$mensaje = "Este correo ha sido enviado desde PHP y capturado por Mailpit.";
$cabeceras = "From: devlocal@example.test";

if (mail($destino, $asunto, $mensaje, $cabeceras)) {
echo "<h1>Correo enviado correctamente</h1>";
echo "<p>Abre Mailpit para verlo.</p>";
} else {
echo "<h1>Error al enviar el correo</h1>";
}

Abrimos:

http://localhost:8080/pruebas/mail.php

Después entramos en Mailpit:

http://localhost:8025

Ahí debería aparecer el correo capturado.


18. Crear script de inicio para Ubuntu y macOS

Creamos el archivo:

DEVLOCAL/_docker/inicio.sh

Contenido:

#!/bin/bash

clear

echo "=============================================="
echo " ENTORNO DEVLOCAL - DOCKER PHP MYSQL"
echo "=============================================="
echo ""

DEV_PATH="$(cd "$(dirname "$0")" && pwd)"

cd "$DEV_PATH" || exit 1

echo "Levantando contenedores DEV..."
echo ""

docker compose up -d

echo ""
echo "Esperando a que los servicios arranquen..."
sleep 3

echo ""
echo "=============================================="
echo " CONTENEDORES ACTIVOS"
echo "=============================================="
echo ""

docker ps --filter "name=DEV_"

echo ""
echo "=============================================="
echo " INFORMACION DE CONEXION"
echo "=============================================="
echo ""

echo "Servidor Apache + PHP:"
echo " URL principal: http://localhost:8080"
echo " Carpeta web: Carpeta DEVLOCAL del alumno"
echo ""

echo "Proyecto de prueba:"
echo " http://localhost:8080/pruebas/"
echo ""

echo "phpMyAdmin:"
echo " URL: http://localhost:8081"
echo " Servidor: mysql"
echo " Usuario root: root"
echo " Password root: root"
echo ""

echo "MySQL desde PHP:"
echo " Host: mysql"
echo " Puerto: 3306"
echo " Base de datos: devdb"
echo " Usuario: devuser"
echo " Password: devpass"
echo ""

echo "MySQL desde el equipo:"
echo " Host: localhost"
echo " Puerto: 3307"
echo " Base de datos: devdb"
echo " Usuario: devuser"
echo " Password: devpass"
echo ""

echo "Mailpit:"
echo " Panel web: http://localhost:8025"
echo " SMTP interno: mailpit:1025"
echo ""

echo "Redis:"
echo " Host desde Docker: redis"
echo " Host desde equipo: localhost"
echo " Puerto: 6379"
echo ""

echo "=============================================="
echo " COMANDOS UTILES"
echo "=============================================="
echo ""

echo "Parar entorno:"
echo " docker compose down"
echo ""

echo "Ver logs:"
echo " docker compose logs -f"
echo ""

echo "Entrar al contenedor PHP:"
echo " docker exec -it DEV_apache_php bash"
echo ""

echo "Entrar a MySQL:"
echo " docker exec -it DEV_mysql mysql -u root -p"
echo ""

echo "=============================================="
echo " ENTORNO DEV LISTO"
echo "=============================================="
echo ""

Damos permisos de ejecución:

chmod +x inicio.sh

Lo ejecutamos:

./inicio.sh

19. Crear script de inicio para Windows

Creamos el archivo:

DEVLOCAL/_docker/inicio.bat

Contenido:

@echo off
cls

echo ==============================================
echo ENTORNO DEVLOCAL - DOCKER PHP MYSQL
echo ==============================================
echo.

cd /d "%~dp0"

echo Levantando contenedores DEV...
echo.

docker compose up -d

echo.
echo Esperando a que los servicios arranquen...
timeout /t 3 > nul

echo.
echo ==============================================
echo CONTENEDORES ACTIVOS
echo ==============================================
echo.

docker ps --filter "name=DEV_"

echo.
echo ==============================================
echo INFORMACION DE CONEXION
echo ==============================================
echo.

echo Servidor Apache + PHP:
echo URL principal: http://localhost:8080
echo Carpeta web: Carpeta DEVLOCAL del alumno
echo.

echo Proyecto de prueba:
echo http://localhost:8080/pruebas/
echo.

echo phpMyAdmin:
echo URL: http://localhost:8081
echo Servidor: mysql
echo Usuario root: root
echo Password root: root
echo.

echo MySQL desde PHP:
echo Host: mysql
echo Puerto: 3306
echo Base de datos: devdb
echo Usuario: devuser
echo Password: devpass
echo.

echo MySQL desde Windows:
echo Host: localhost
echo Puerto: 3307
echo Base de datos: devdb
echo Usuario: devuser
echo Password: devpass
echo.

echo Mailpit:
echo Panel web: http://localhost:8025
echo SMTP interno: mailpit:1025
echo.

echo Redis:
echo Host desde Docker: redis
echo Host desde Windows: localhost
echo Puerto: 6379
echo.

echo ==============================================
echo COMANDOS UTILES
echo ==============================================
echo.

echo Parar entorno:
echo docker compose down
echo.

echo Ver logs:
echo docker compose logs -f
echo.

echo Entrar al contenedor PHP:
echo docker exec -it DEV_apache_php bash
echo.

echo Entrar a MySQL:
echo docker exec -it DEV_mysql mysql -u root -p
echo.

echo ==============================================
echo ENTORNO DEV LISTO
echo ==============================================
echo.

pause

Para ejecutarlo, el alumno puede hacer doble clic sobre inicio.bat o ejecutarlo desde PowerShell.


20. Script para parar el entorno

Ubuntu y macOS

Creamos:

DEVLOCAL/_docker/parar.sh

Contenido:

#!/bin/bash

cd "$(dirname "$0")" || exit 1

echo "Parando entorno DEV..."
docker compose down

echo "Entorno detenido."

Permisos:

chmod +x parar.sh

Ejecución:

./parar.sh

Windows

Creamos:

DEVLOCAL/_docker/parar.bat

Contenido:

@echo off
cls

cd /d "%~dp0"

echo Parando entorno DEV...
docker compose down

echo.
echo Entorno detenido.
pause

21. Comandos básicos que debe conocer el alumno

Levantar contenedores

docker compose up -d

Levantar y reconstruir

docker compose up -d --build

Parar contenedores

docker compose down

Ver contenedores activos

docker ps

Ver todos los contenedores

docker ps -a

Ver logs

docker compose logs -f

Ver logs de un servicio concreto

docker compose logs -f apache_php

Entrar al contenedor de PHP

docker exec -it DEV_apache_php bash

Entrar al contenedor de MySQL

docker exec -it DEV_mysql mysql -u root -p

Contraseña:

root

22. Crear varios proyectos web

El alumno puede crear diferentes carpetas dentro de DEVLOCAL.

Por ejemplo:

DEVLOCAL/
├── pruebas/
├── tienda/
├── blog/
├── reservas/
└── ejercicios_php/

Cada proyecto se abrirá desde el navegador así:

http://localhost:8080/pruebas/
http://localhost:8080/tienda/
http://localhost:8080/blog/
http://localhost:8080/reservas/
http://localhost:8080/ejercicios_php/

23. Ejercicio práctico

Parte 1: Comprobar PHP

Crear una carpeta llamada:

alumno_php

Dentro crear un archivo:

index.php

Con este contenido:

<?php

$nombre = "Alumno";
$curso = "Desarrollo Web con PHP";

echo "<h1>Hola, $nombre</h1>";
echo "<p>Estamos trabajando en el curso de $curso.</p>";

Abrir:

http://localhost:8080/alumno_php/

Parte 2: Comprobar MySQL

Crear un archivo:

conexion.php

Contenido:

<?php

$conexion = new mysqli("mysql", "devuser", "devpass", "devdb");

if ($conexion->connect_error) {
die("Error: " . $conexion->connect_error);
}

echo "Conexión correcta con MySQL";

Abrir:

http://localhost:8080/alumno_php/conexion.php

Parte 3: Crear una tabla desde phpMyAdmin

Entrar en:

http://localhost:8081

Seleccionar la base de datos:

devdb

Crear una tabla llamada:

alumnos

Con estos campos:

CampoTipoExtra
idINTAUTO_INCREMENT, PRIMARY KEY
nombreVARCHAR(100)
emailVARCHAR(150)
fecha_altaDATETIME

SQL:

CREATE TABLE alumnos (
id INT AUTO_INCREMENT PRIMARY KEY,
nombre VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL,
fecha_alta DATETIME DEFAULT CURRENT_TIMESTAMP
);

Insertar datos:

INSERT INTO alumnos (nombre, email) VALUES
('Ana', 'ana@example.test'),
('Luis', 'luis@example.test'),
('Marta', 'marta@example.test');

Parte 4: Leer datos desde PHP

Crear:

listar.php

Contenido:

<?php

$conexion = new mysqli("mysql", "devuser", "devpass", "devdb");

if ($conexion->connect_error) {
die("Error: " . $conexion->connect_error);
}

$resultado = $conexion->query("SELECT * FROM alumnos");

echo "<h1>Listado de alumnos</h1>";

echo "<table border='1' cellpadding='8'>";
echo "<tr>";
echo "<th>ID</th>";
echo "<th>Nombre</th>";
echo "<th>Email</th>";
echo "<th>Fecha de alta</th>";
echo "</tr>";

while ($fila = $resultado->fetch_assoc()) {
echo "<tr>";
echo "<td>" . $fila["id"] . "</td>";
echo "<td>" . $fila["nombre"] . "</td>";
echo "<td>" . $fila["email"] . "</td>";
echo "<td>" . $fila["fecha_alta"] . "</td>";
echo "</tr>";
}

echo "</table>";

$conexion->close();

Abrir:

http://localhost:8080/alumno_php/listar.php

24. Preguntas de reflexión para el alumno

  1. ¿Qué diferencia hay entre instalar Apache, PHP y MySQL directamente en el sistema y hacerlo con Docker?
  2. ¿Qué ventaja tiene que todos los servicios estén definidos en un archivo docker-compose.yml?
  3. ¿Por qué PHP se conecta a MySQL usando el host mysql y no localhost?
  4. ¿Qué es un volumen en Docker?
  5. ¿Dónde se guardan los datos de MySQL en este proyecto?
  6. ¿Qué pasaría si ejecutamos docker compose down -v?
  7. ¿Para qué sirve phpMyAdmin?
  8. ¿Para qué sirve Mailpit?
  9. ¿Por qué no deberíamos usar contraseñas como root o devpass en producción?
  10. ¿Qué diferencia hay entre un entorno de desarrollo y un entorno de producción?

25. Problemas frecuentes

Docker no arranca en Windows

Posibles causas:

  • Docker Desktop no está abierto.
  • WSL 2 no está instalado o activado.
  • La virtualización está desactivada en BIOS/UEFI.
  • El equipo necesita reiniciarse.

Docker recomienda usar el backend WSL 2 en Windows para Docker Desktop.


El puerto 8080 ya está ocupado

Puede ocurrir si otro servicio ya está usando ese puerto.

Solución: cambiar en docker-compose.yml:

ports:
- "8080:80"

Por ejemplo:

ports:
- "8090:80"

Después habría que entrar por:

http://localhost:8090

El puerto 3307 ya está ocupado

Cambiar:

ports:
- "3307:3306"

Por ejemplo:

ports:
- "3308:3306"

No aparecen los cambios en PHP

Probar a recargar el navegador con:

Ctrl + F5

También se puede reiniciar el contenedor:

docker compose restart apache_php

Error de permisos en Ubuntu

Si Docker pide sudo, puede faltar añadir el usuario al grupo docker.

sudo usermod -aG docker $USER

Después hay que cerrar sesión y volver a entrar.


phpMyAdmin no conecta

Comprobar que MySQL está activo:

docker ps

También se pueden ver los logs:

docker compose logs -f mysql

26. Cómo borrar todo y empezar de nuevo

Para parar los contenedores:

docker compose down

Para parar y borrar también los datos de MySQL:

docker compose down -v

Cuidado: este comando borra el volumen de MySQL. Si hay bases de datos creadas, se perderán.


29. Ampliaciones posibles

Cuando el entorno básico funcione, se pueden añadir mejoras:

  • Crear dominios locales como tienda.localhost.
  • Añadir HTTPS local.
  • Añadir un contenedor de Node.js.
  • Añadir un contenedor específico para Laravel.
  • Crear plantillas para WordPress.
  • Añadir copias de seguridad automáticas de MySQL.
  • Crear un script para exportar e importar bases de datos.
  • Crear varios entornos: desarrollo, pruebas y producción.

30. Conclusión

Con esta práctica hemos creado un entorno de desarrollo web completo usando Docker. El resultado es similar a XAMPP o MAMP, pero con una ventaja importante: todo el entorno queda definido mediante archivos.

Esto permite:

  • Repetir la instalación en diferentes sistemas operativos.
  • Compartir el entorno con otros compañeros.
  • Evitar conflictos con instalaciones locales.
  • Trabajar con varios servicios a la vez.
  • Preparar al alumno para entornos profesionales basados en contenedores.

Docker Compose facilita levantar todos los servicios con un solo comando, lo que lo convierte en una herramienta especialmente útil para desarrollo web moderno.

Script Cerrar

Además del script inicio, vamos a crear un script llamado cerrar. Este script no solamente permite apagar el entorno, sino también eliminarlo de diferentes formas según lo que necesitemos. Esto es importante porque no siempre queremos borrar los datos. A veces solo queremos detener los contenedores, y otras veces queremos empezar desde cero.


Diferencia entre las opciones

OpciónComando¿Borra contenedores?¿Borra datos MySQL?¿Borra imágenes?
Parardocker compose stopNoNoNo
Eliminar contenedoresdocker compose downNoNo
Eliminar con volúmenesdocker compose down -vNo
Destruir completodocker compose down -v --rmi local

docker compose stop

Detiene los contenedores, pero no los elimina.

Es como apagar una máquina virtual.


docker compose down

Detiene y elimina los contenedores, pero mantiene los volúmenes.

Es decir, si teníamos una base de datos MySQL con datos, normalmente se conservará.


docker compose down -v

Detiene y elimina los contenedores, y también borra los volúmenes.

En este proyecto significa que se borrarán los datos de MySQL.


docker compose down -v --rmi local

Además de eliminar contenedores y volúmenes, elimina imágenes locales creadas por el proyecto.

En nuestro caso, puede borrar la imagen personalizada de Apache + PHP, por lo que en el siguiente arranque habrá que reconstruirla con:

docker compose up -d --build

Recomendación para uso diario

Para el día a día, lo normal es usar la opción:

1) Parar contenedores

o:

2) Parar y eliminar contenedores

La opción 3 y 4 solo deberían usarse cuando queramos empezar desde cero.

Especialmente la opción 3:

docker compose down -v

porque borra los datos de MySQL.

Script para Ubuntu y macOS: cerrar.sh

Crear el archivo:

nano /Users/antoniooteroveiga/DEVLOCAL/_docker/cerrar.sh

Contenido:

#!/bin/bash

clear

echo "=============================================="
echo " CERRAR ENTORNO DEVLOCAL"
echo "=============================================="
echo ""

DEV_PATH="$(cd "$(dirname "$0")" && pwd)"
cd "$DEV_PATH" || exit 1

echo "Este script permite cerrar o destruir el entorno Docker DEV."
echo ""
echo "Elige una opcion:"
echo ""
echo " 1) Parar contenedores"
echo " Equivale a: docker compose stop"
echo ""
echo " 2) Parar y eliminar contenedores"
echo " Equivale a: docker compose down"
echo ""
echo " 3) Parar, eliminar contenedores y borrar volumenes"
echo " Equivale a: docker compose down -v"
echo " AVISO: se borraran las bases de datos de MySQL."
echo ""
echo " 4) Parar, eliminar contenedores, volumenes e imagenes del proyecto"
echo " Equivale a: docker compose down -v --rmi local"
echo " AVISO: se borraran las bases de datos y las imagenes creadas localmente."
echo ""
echo " 5) Ver contenedores DEV activos"
echo ""
echo " 6) Cancelar"
echo ""

read -p "Selecciona una opcion [1-6]: " opcion

echo ""

case "$opcion" in

1)
echo "Parando contenedores..."
docker compose stop
echo ""
echo "Contenedores detenidos."
;;

2)
echo "Parando y eliminando contenedores..."
docker compose down
echo ""
echo "Contenedores eliminados. Los volumenes se conservan."
;;

3)
echo "ATENCION: esta opcion borrara los volumenes."
echo "Esto eliminara los datos persistentes de MySQL."
echo ""
read -p "Escribe BORRAR para confirmar: " confirmacion

if [ "$confirmacion" = "BORRAR" ]; then
echo ""
echo "Eliminando contenedores y volumenes..."
docker compose down -v
echo ""
echo "Entorno eliminado con volumenes."
else
echo ""
echo "Operacion cancelada. No se ha borrado nada."
fi
;;

4)
echo "ATENCION: esta opcion borrara contenedores, volumenes e imagenes locales."
echo "Esto eliminara los datos de MySQL y obligara a reconstruir la imagen PHP."
echo ""
read -p "Escribe DESTRUIR para confirmar: " confirmacion

if [ "$confirmacion" = "DESTRUIR" ]; then
echo ""
echo "Eliminando contenedores, volumenes e imagenes locales..."
docker compose down -v --rmi local
echo ""
echo "Entorno destruido."
else
echo ""
echo "Operacion cancelada. No se ha borrado nada."
fi
;;

5)
echo "Mostrando contenedores DEV..."
echo ""
docker ps -a --filter "name=DEV_"
;;

6)
echo "Operacion cancelada."
;;

*)
echo "Opcion no valida."
;;

esac

echo ""
echo "=============================================="
echo " PROCESO FINALIZADO"
echo "=============================================="
echo ""

Dar permisos de ejecución:

chmod +x /Users/antoniooteroveiga/DEVLOCAL/_docker/cerrar.sh

Ejecutarlo:

cd /Users/antoniooteroveiga/DEVLOCAL/_docker
./cerrar.sh

Versión más portable

Si quieres que funcione sin depender de tu usuario concreto, es mejor decirles que creen el archivo dentro de _docker y que lo ejecuten desde ahí.

cd ~/DEVLOCAL/_docker
nano cerrar.sh
chmod +x cerrar.sh
./cerrar.sh

El script ya detecta automáticamente la carpeta donde está, gracias a esta línea:

DEV_PATH="$(cd "$(dirname "$0")" && pwd)"

Por eso vale tanto para Ubuntu como para macOS.


Script para Windows: cerrar.bat

Crear el archivo:

C:\DEVLOCAL\_docker\cerrar.bat

Contenido:

@echo off
cls

cd /d "%~dp0"

:menu
cls
echo ==============================================
echo CERRAR ENTORNO DEVLOCAL
echo ==============================================
echo.
echo Este script permite cerrar o destruir el entorno Docker DEV.
echo.
echo Elige una opcion:
echo.
echo 1) Parar contenedores
echo Equivale a: docker compose stop
echo.
echo 2) Parar y eliminar contenedores
echo Equivale a: docker compose down
echo.
echo 3) Parar, eliminar contenedores y borrar volumenes
echo Equivale a: docker compose down -v
echo AVISO: se borraran las bases de datos de MySQL.
echo.
echo 4) Parar, eliminar contenedores, volumenes e imagenes del proyecto
echo Equivale a: docker compose down -v --rmi local
echo AVISO: se borraran las bases de datos y las imagenes creadas localmente.
echo.
echo 5) Ver contenedores DEV activos
echo.
echo 6) Cancelar
echo.

set /p opcion=Selecciona una opcion [1-6]:

if "%opcion%"=="1" goto parar
if "%opcion%"=="2" goto eliminar
if "%opcion%"=="3" goto volumenes
if "%opcion%"=="4" goto destruir
if "%opcion%"=="5" goto ver
if "%opcion%"=="6" goto cancelar

echo.
echo Opcion no valida.
pause
goto menu

:parar
cls
echo Parando contenedores...
echo.
docker compose stop
echo.
echo Contenedores detenidos.
pause
goto fin

:eliminar
cls
echo Parando y eliminando contenedores...
echo.
docker compose down
echo.
echo Contenedores eliminados. Los volumenes se conservan.
pause
goto fin

:volumenes
cls
echo ATENCION: esta opcion borrara los volumenes.
echo Esto eliminara los datos persistentes de MySQL.
echo.
set /p confirmacion=Escribe BORRAR para confirmar:

if "%confirmacion%"=="BORRAR" (
echo.
echo Eliminando contenedores y volumenes...
docker compose down -v
echo.
echo Entorno eliminado con volumenes.
) else (
echo.
echo Operacion cancelada. No se ha borrado nada.
)

pause
goto fin

:destruir
cls
echo ATENCION: esta opcion borrara contenedores, volumenes e imagenes locales.
echo Esto eliminara los datos de MySQL y obligara a reconstruir la imagen PHP.
echo.
set /p confirmacion=Escribe DESTRUIR para confirmar:

if "%confirmacion%"=="DESTRUIR" (
echo.
echo Eliminando contenedores, volumenes e imagenes locales...
docker compose down -v --rmi local
echo.
echo Entorno destruido.
) else (
echo.
echo Operacion cancelada. No se ha borrado nada.
)

pause
goto fin

:ver
cls
echo Mostrando contenedores DEV...
echo.
docker ps -a --filter "name=DEV_"
echo.
pause
goto menu

:cancelar
cls
echo Operacion cancelada.
pause
goto fin

:fin
cls
echo ==============================================
echo PROCESO FINALIZADO
echo ==============================================
echo.