Docker Compose permite describir en un único archivo YAML todos los contenedores de una aplicación, con sus redes, volúmenes y variables, y gestionarlos juntos con un solo comando. En este tutorial desplegarás en Ubuntu 24.04 un WordPress con su base de datos MariaDB usando Compose, guardarás las credenciales fuera del archivo principal, harás que WordPress espere a que la base de datos esté lista y aprenderás los comandos para operar, actualizar y eliminar la pila.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 1 GB de RAM.
- Docker Engine y el plugin
docker-compose-plugininstalados desde el repositorio oficial de Docker. - Un usuario no root con privilegios
sudoy miembro del grupodocker.
Comprueba que tienes Compose v2:
docker compose version
Docker Compose version v2.39.2
El comando actual es docker compose (con espacio). El antiguo binario docker-compose escrito en Python está abandonado desde 2023; si tus scripts lo usan, cámbialos a la nueva sintaxis.
Paso 1: Crear el directorio del proyecto
Compose usa el nombre del directorio como nombre del proyecto, que sirve de prefijo para contenedores, redes y volúmenes. Crea uno para la pila:
mkdir -p ~/wordpress && cd ~/wordpress
Paso 2: Guardar las credenciales en un archivo .env
Compose lee automáticamente el archivo .env del directorio del proyecto y sustituye sus valores en compose.yaml. Así las contraseñas no quedan en el archivo que versionas.
nano .env
MARIADB_ROOT_PASSWORD=your_root_password
MARIADB_PASSWORD=your_db_password
WP_PORT=8080
Sustituye your_root_password y your_db_password por contraseñas largas y distintas; puedes generarlas con openssl rand -base64 24. Restringe los permisos del archivo:
chmod 600 .env
ImportanteSi guardas el proyecto en Git, añade
.enva.gitignore.
Paso 3: Escribir el archivo compose.yaml
El nombre recomendado del archivo es compose.yaml (también se aceptan compose.yml y el antiguo docker-compose.yml). Crea el archivo:
nano compose.yaml
services:
db:
image: mariadb:11.4
restart: unless-stopped
environment:
MARIADB_DATABASE: wordpress
MARIADB_USER: wordpress
MARIADB_PASSWORD: ${MARIADB_PASSWORD:?define MARIADB_PASSWORD en .env}
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD:?define MARIADB_ROOT_PASSWORD en .env}
volumes:
- db_data:/var/lib/mysql
networks:
- backend
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
wordpress:
image: wordpress:php8.3-apache
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: ${MARIADB_PASSWORD}
ports:
- "127.0.0.1:${WP_PORT:-8080}:80"
volumes:
- wp_data:/var/www/html
networks:
- backend
volumes:
db_data:
wp_data:
networks:
backend:
Los bloques del archivo son:
services: cada entrada es un contenedor.imageindica la imagen (con etiqueta fija),restartla política de reinicio,environmentlas variables yvolumeslos datos persistentes.${VARIABLE}: se sustituye con el valor de.env. La forma${VAR:?mensaje}hace que Compose se niegue a arrancar si la variable no está definida, y${VAR:-8080}aplica un valor por defecto.depends_onconcondition: service_healthy: WordPress no arranca hasta que el healthcheck de MariaDB da positivo. Sin la condición, Compose solo esperaría a que el contenedor existiera, no a que la base de datos aceptara conexiones.healthcheck: la imagen oficial de MariaDB incluye el scripthealthcheck.sh, que comprueba la conexión y que InnoDB está inicializado.networks: los servicios de la misma red se localizan por su nombre. Por esoWORDPRESS_DB_HOSTes simplementedb.volumes(nivel superior): declara volúmenes con nombre que sobreviven a la eliminación de los contenedores.
Ya no hace falta la clave version: al principio del archivo. Compose la ignora y muestra un aviso de que está obsoleta.
El puerto se publica solo en 127.0.0.1, porque los puertos que publica Docker no pasan por UFW. Para exponer el sitio lo correcto es poner delante un proxy inverso con HTTPS (Nginx o Caddy) que reenvíe a 127.0.0.1:8080.
Antes de arrancar, valida el archivo y comprueba cómo quedan las variables sustituidas:
docker compose config
Si hay un error de sintaxis YAML o falta una variable obligatoria, Compose lo indica aquí con la línea exacta. Ten en cuenta que la salida muestra las contraseñas en claro.
Paso 4: Arrancar la pila
Descarga las imágenes, crea la red y los volúmenes y arranca los contenedores en segundo plano:
docker compose up -d
[+] Running 5/5
Network wordpress_backend Created
Volume "wordpress_db_data" Created
Volume "wordpress_wp_data" Created
Container wordpress-db-1 Healthy
Container wordpress-wordpress-1 Started
Observa que el contenedor de WordPress arranca después de que db pase a Healthy. Consulta el estado de los servicios:
docker compose ps
NAME IMAGE SERVICE STATUS PORTS
wordpress-db-1 mariadb:11.4 db Up 40 seconds (healthy) 3306/tcp
wordpress-wordpress-1 wordpress:php8.3-apache wordpress Up 12 seconds 127.0.0.1:8080->80/tcp
Comprueba que WordPress responde y redirige al asistente de instalación:
curl -I http://127.0.0.1:8080
HTTP/1.1 302 Found
Location: http://127.0.0.1:8080/wp-admin/install.php
Para completar la instalación desde tu navegador sin exponer el puerto, abre un túnel SSH desde tu equipo con ssh -L 8080:127.0.0.1:8080 your_user@your_server_ip y visita http://localhost:8080.
Paso 5: Operar los servicios
Todos los comandos de Compose se ejecutan desde el directorio del proyecto y aceptan el nombre de un servicio para actuar solo sobre él.
Ver los logs de un servicio y seguirlos en tiempo real:
docker compose logs -f --tail 50 wordpress
Ejecutar un comando dentro de un servicio en marcha, por ejemplo una consola de MariaDB (te pedirá la contraseña de wordpress):
docker compose exec db mariadb -u wordpress -p wordpress
Comprueba que las tablas existen una vez completada la instalación web:
SHOW TABLES;
Escribe exit para salir. Otros comandos habituales:
| Comando | Efecto |
|---|---|
docker compose stop | Detiene los contenedores sin eliminarlos |
docker compose start | Arranca los contenedores detenidos |
docker compose restart wordpress | Reinicia un servicio |
docker compose top | Procesos en ejecución de cada servicio |
docker compose down | Detiene y elimina contenedores y redes. Los volúmenes se conservan |
Paso 6: Cambiar la configuración y actualizar imágenes
Compose compara el estado actual con compose.yaml y solo recrea lo que ha cambiado. Por ejemplo, para limitar la memoria de la base de datos, añade la clave mem_limit al servicio db:
nano compose.yaml
db:
image: mariadb:11.4
restart: unless-stopped
mem_limit: 512m
Aplica el cambio:
docker compose up -d
Container wordpress-db-1 Recreated
Container wordpress-wordpress-1 Running
Solo se recrea db; los datos siguen en el volumen wordpress_db_data.
Para actualizar a las últimas versiones publicadas de las etiquetas que usas, descarga las imágenes y recrea los contenedores que hayan cambiado:
docker compose pull
docker compose up -d
Después elimina las imágenes antiguas que ya no usa ningún contenedor:
docker image prune
ConsejoHaz una copia de la base de datos antes de actualizar, por ejemplo con
docker compose exec -T db sh -c 'mariadb-dump -u root -p"$MARIADB_ROOT_PASSWORD" --all-databases' > backup.sql. Cambiar de versión mayor de MariaDB (por ejemplo, de 10.11 a 11.4) requiere revisar las notas de actualización de la imagen.
Paso 7: Separar la configuración de desarrollo
Si existe un archivo compose.override.yaml junto a compose.yaml, Compose lo combina automáticamente. Es útil para ajustes que solo quieres en tu máquina local, por ejemplo montar un tema de WordPress en desarrollo:
nano compose.override.yaml
services:
wordpress:
volumes:
- ./mi-tema:/var/www/html/wp-content/themes/mi-tema
environment:
WORDPRESS_DEBUG: "1"
En el servidor de producción no copies el archivo de override, o indica explícitamente qué archivos usar con -f:
docker compose -f compose.yaml up -d
Paso 8: Detener y eliminar la pila
Para eliminar contenedores y redes conservando los datos:
docker compose down
Si vuelves a ejecutar docker compose up -d, WordPress arrancará con todo su contenido. Para borrarlo todo, volúmenes incluidos:
docker compose down -v
Advertencia
down -velimina de forma permanente la base de datos y los archivos de WordPress.
Solución de problemas
required variable MARIADB_PASSWORD is missing a value. Falta el archivo .env o la variable en él. Compose busca .env en el directorio del proyecto, que por defecto es el directorio donde está compose.yaml.
dependency failed to start: container wordpress-db-1 is unhealthy. MariaDB no ha arrancado bien. Revisa docker compose logs db. Si cambiaste las contraseñas de .env después del primer arranque, ten en cuenta que MariaDB solo las aplica al inicializar un volumen vacío.
WordPress muestra Error establishing a database connection. Comprueba que WORDPRESS_DB_PASSWORD y MARIADB_PASSWORD coinciden y que ambos servicios están en la misma red con docker compose config.
Conclusión
Has desplegado una aplicación de dos servicios con Docker Compose, con credenciales en .env, volúmenes persistentes, una red interna y un arranque ordenado mediante healthchecks, y conoces los comandos para operarla y actualizarla. Como siguientes pasos, pon un proxy inverso con HTTPS delante de WordPress, programa copias de seguridad de los volúmenes y convierte tus propias aplicaciones en servicios de Compose a partir de su Dockerfile.
