WordPress con Docker Compose: Guía Completa Producción 2025

¿Quieres montar WordPress en minutos sin líos de Apache, PHP, MySQL a mano? Docker Compose lo hace trivial: un archivo YAML, un comando, y WordPress corriendo. En esta guía aprenderás desde setup básico hasta producción con HTTPS, backups automáticos, y optimización de performance.

En esta guía aprenderás:

  • 3 métodos instalación: básico, producción, producción+ con Nginx
  • Configuración segura con .env para secretos
  • HTTPS con Let’s Encrypt (Caddy reverse proxy)
  • Backups automáticos (database + archivos)
  • Optimización performance (cache, PHP-FPM tuning)
  • Migración desde WordPress existente
  • Troubleshooting problemas comunes

🚀 Método 1: WordPress Básico (Testing/Desarrollo)

Setup mínimo para probar WordPress localmente.

Crear carpeta y archivos:

mkdir ~/wordpress-docker && cd ~/wordpress-docker
nano docker-compose.yml

docker-compose.yml básico:

version: '3.8'

services:
  db:
    image: mysql:8.0
    container_name: wordpress_db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: wppassword
    volumes:
      - db_data:/var/lib/mysql

  wordpress:
    image: wordpress:latest
    container_name: wordpress
    restart: always
    ports:
      - "8000:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: wppassword
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wp_data:/var/www/html
    depends_on:
      - db

volumes:
  db_data:
  wp_data:

Arrancar:

docker compose up -d

Acceder: http://localhost:8000

Completar wizard WordPress (idioma, admin user, password)

🔒 Método 2: Producción con Variables de Entorno

Mejor práctica: secretos en .env file separado.

Crear .env:

# Database
MYSQL_ROOT_PASSWORD=cambiar_esto_root_password_seguro
MYSQL_DATABASE=wordpress
MYSQL_USER=wpuser
MYSQL_PASSWORD=cambiar_esto_password_muy_seguro

# WordPress
WORDPRESS_DB_HOST=db:3306
WORDPRESS_DB_USER=wpuser
WORDPRESS_DB_PASSWORD=cambiar_esto_password_muy_seguro
WORDPRESS_DB_NAME=wordpress

# Domain
WORDPRESS_URL=https://tudominio.com

docker-compose.yml producción:

version: '3.8'

services:
  db:
    image: mysql:8.0
    container_name: wordpress_db
    restart: unless-stopped
    env_file: .env
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    command: '--default-authentication-plugin=mysql_native_password'

  wordpress:
    image: wordpress:6.4-php8.2-apache
    container_name: wordpress
    restart: unless-stopped
    env_file: .env
    environment:
      WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST}
      WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
      WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
      WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
      WORDPRESS_CONFIG_EXTRA: |
        define('WP_HOME', '${WORDPRESS_URL}');
        define('WP_SITEURL', '${WORDPRESS_URL}');
        define('WP_DEBUG', false);
        define('WP_DEBUG_LOG', false);
    volumes:
      - wp_data:/var/www/html
    depends_on:
      - db

volumes:
  db_data:
  wp_data:

Notar:

  • Versión específica WordPress (no :latest)
  • Secrets en .env (no hardcoded)
  • restart: unless-stopped (auto-restart excepto manual stop)
  • MySQL authentication plugin (compatibilidad)

🌐 Método 3: Producción + HTTPS (Caddy Reverse Proxy)

WordPress con certificado SSL automático via Let’s Encrypt.

docker-compose.yml completo:

version: '3.8'

services:
  db:
    image: mysql:8.0
    container_name: wordpress_db
    restart: unless-stopped
    env_file: .env
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - wordpress
    command: '--default-authentication-plugin=mysql_native_password'

  wordpress:
    image: wordpress:6.4-php8.2-apache
    container_name: wordpress
    restart: unless-stopped
    env_file: .env
    environment:
      WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST}
      WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
      WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
      WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
      WORDPRESS_CONFIG_EXTRA: |
        define('WP_HOME', '${WORDPRESS_URL}');
        define('WP_SITEURL', '${WORDPRESS_URL}');
        define('FORCE_SSL_ADMIN', true);
        if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false)
           $_SERVER['HTTPS']='on';
    volumes:
      - wp_data:/var/www/html
    networks:
      - wordpress
    depends_on:
      - db

  caddy:
    image: caddy:latest
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - wordpress

networks:
  wordpress:
    driver: bridge

volumes:
  db_data:
  wp_data:
  caddy_data:
  caddy_config:

Caddyfile:

tudominio.com {
    reverse_proxy wordpress:80
}

Caddy obtiene certificado SSL automáticamente. Accede: https://tudominio.com

💾 Backups Automáticos

Backup Database + Archivos

Script backup completo: ~/scripts/backup-wordpress.sh

#!/bin/bash
BACKUP_DIR="/home/user/backups/wordpress"
DATE=$(date +%Y-%m-%d_%H-%M-%S)
WP_DIR="/home/user/wordpress-docker"

mkdir -p "$BACKUP_DIR"

# Backup MySQL
docker exec wordpress_db mysqldump -u root -p${MYSQL_ROOT_PASSWORD} wordpress | \
  gzip > "$BACKUP_DIR/wordpress-db-${DATE}.sql.gz"

# Backup archivos WordPress (uploads, themes, plugins)
tar -czf "$BACKUP_DIR/wordpress-files-${DATE}.tar.gz" \
  -C "$WP_DIR" wp_data

# Limpiar backups antiguos (30 días)
find "$BACKUP_DIR" -name "wordpress-*" -mtime +30 -delete

echo "Backup completado:"
echo "  - wordpress-db-${DATE}.sql.gz"
echo "  - wordpress-files-${DATE}.tar.gz"

Permisos y cron:

chmod +x ~/scripts/backup-wordpress.sh

# Backup diario 3am
crontab -e
0 3 * * * /home/user/scripts/backup-wordpress.sh >> /home/user/logs/wordpress-backup.log 2>&1

Restaurar desde Backup

# Parar contenedores
docker compose down

# Restaurar database
gunzip < /home/user/backups/wordpress/wordpress-db-2025-11-01.sql.gz | \
  docker exec -i wordpress_db mysql -u root -p${MYSQL_ROOT_PASSWORD} wordpress

# Restaurar archivos
rm -rf wp_data
tar -xzf /home/user/backups/wordpress/wordpress-files-2025-11-01.tar.gz

# Reiniciar
docker compose up -d

⚡ Optimización Performance

PHP-FPM Tuning

Crear custom php.ini:

upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
max_execution_time = 300
max_input_vars = 3000

Montar en docker-compose.yml:

wordpress:
  volumes:
    - wp_data:/var/www/html
    - ./custom-php.ini:/usr/local/etc/php/conf.d/custom.ini:ro

Redis Cache

Añadir Redis al stack:

services:
  redis:
    image: redis:alpine
    container_name: wordpress_redis
    restart: unless-stopped
    networks:
      - wordpress

Instalar plugin: Redis Object Cache (desde WordPress admin)

🔄 Migrar WordPress Existente a Docker

Paso 1: Exportar database WordPress antiguo

mysqldump -u usuario -p wordpress_viejo > wordpress_export.sql

Paso 2: Copiar archivos wp-content

tar -czf wp-content.tar.gz /var/www/html/wp-content

Paso 3: Arrancar WordPress Docker nuevo

docker compose up -d

Paso 4: Importar database

cat wordpress_export.sql | docker exec -i wordpress_db mysql -u root -p${MYSQL_ROOT_PASSWORD} wordpress

Paso 5: Copiar wp-content

docker cp wp-content.tar.gz wordpress:/var/www/html/
docker exec wordpress tar -xzf /var/www/html/wp-content.tar.gz -C /var/www/html/
docker exec wordpress chown -R www-data:www-data /var/www/html/wp-content

Paso 6: Actualizar URLs

Si dominio cambió, actualizar en MySQL:

docker exec -it wordpress_db mysql -u root -p${MYSQL_ROOT_PASSWORD} wordpress

UPDATE wp_options SET option_value='https://nuevodominio.com' WHERE option_name='siteurl';
UPDATE wp_options SET option_value='https://nuevodominio.com' WHERE option_name='home';

🔧 Troubleshooting

Error: "Error establishing database connection"

Causa: WordPress arranca antes que MySQL esté listo

Solución: Añadir healthcheck

db:
  healthcheck:
    test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
    timeout: 20s
    retries: 10

wordpress:
  depends_on:
    db:
      condition: service_healthy

Permisos archivos incorrectos

Síntoma: No puedes subir media, instalar plugins

Solución:

docker exec wordpress chown -R www-data:www-data /var/www/html
docker exec wordpress find /var/www/html -type d -exec chmod 755 {} \;
docker exec wordpress find /var/www/html -type f -exec chmod 644 {} \;

WordPress muy lento

Causas:

  • No hay cache (instalar Redis Object Cache)
  • PHP memory_limit bajo (aumentar a 256M)
  • Muchos plugins pesados (desactivar innecesarios)

📊 Comparativa: WordPress Docker vs Tradicional

Aspecto Docker Tradicional (LAMP)
Setup tiempo 5 minutos 30-60 minutos
Configuración docker-compose.yml Apache/Nginx + PHP + MySQL manual
Portabilidad ✅ Funciona igual en cualquier servidor ⚠️ Depende del OS
Múltiples WordPress ✅ Fácil (carpetas separadas) ⚠️ Complejo (virtual hosts)
Updates docker compose pull && restart apt update && upgrade (puede romper)
Backups Volúmenes fáciles de copiar Carpetas dispersas (/var/www, /var/lib/mysql)
Rollback ✅ Cambiar tag imagen ⚠️ Difícil sin backup completo
Performance Similar (overhead mínimo) Similar

🔗 Recursos Adicionales

❓ Preguntas Frecuentes

¿WordPress Docker es tan rápido como instalación tradicional?

Sí, performance casi idéntica. Docker overhead es <2%. Con optimizaciones (Redis cache, PHP tuning) puede ser incluso más rápido que LAMP tradicional mal configurado.

¿Puedo usar plugins y themes normales?

Sí, 100%. WordPress Docker es WordPress oficial. Todos los plugins/themes funcionan igual. Instalas desde admin panel como siempre.

¿Cómo actualizar WordPress en Docker?

Dos opciones: 1) Desde admin panel WordPress (update automático como siempre), 2) Cambiar tag imagen en docker-compose.yml (wordpress:6.4wordpress:6.5) y docker compose up -d. Opción 1 recomendada para minor updates, opción 2 para control total.

¿Qué pasa con mis datos si borro contenedores?

Datos persisten en volúmenes Docker (db_data, wp_data). Puedes borrar contenedores (docker compose down) y recrearlos (docker compose up -d) sin perder nada. Para borrar TODO incluyendo datos: docker compose down -v (cuidado!).

¿Puedo tener múltiples WordPress en mismo servidor?

Sí, fácil. Crea carpetas separadas (~/wp1, ~/wp2) cada una con su docker-compose.yml. Cambia puertos (8000, 8001) o usa reverse proxy (Caddy/Nginx) con dominios diferentes. Comparten host pero contenedores aislados.

¿Necesito saber Docker para usar esto?

No. Con copiar docker-compose.yml, editar .env con tus passwords, y correr docker compose up -d funciona. Para troubleshooting básico útil saber docker logs wordpress y docker exec -it wordpress bash.

¿WordPress Docker funciona en Windows/Mac?

Sí, Docker Desktop (Windows/Mac) soporta docker-compose. Funciona idéntico. Solo cambia rutas volúmenes (en Windows usar C:\Users\...). En producción recomendado Linux por performance.

¿Cómo hacer backup antes de actualizar WordPress?

Usa script backup mostrado arriba. Antes de update mayor: ./backup-wordpress.sh, verificar backup existe, luego actualizar. Si rompe algo, restaurar desde backup. Proceso tarda 2 minutos, previene dolores de cabeza.

¿Puedo usar MariaDB en vez de MySQL?

Sí, cambia imagen: image: mariadb:11. Variables entorno casi iguales. MariaDB suele ser más rápido que MySQL para WordPress. Recomendado si empiezas desde cero.

¿WordPress Docker consume más recursos que tradicional?

Overhead Docker: ~50-100 MB RAM extra. Irrelevante en servidores modernos. A cambio ganas: aislamiento, portabilidad, facilidad management. Trade-off vale totalmente la pena.

¿Cómo habilitar HTTPS si no tengo dominio?

Opciones: 1) Certificado self-signed (navegador dará warning, ok para desarrollo), 2) Cloudflare Tunnel (gratis, sin dominio propio necesario), 3) Comprar dominio (~$10/año). Para producción seria recomiendo opción 3.

¿WordPress Docker soporta Multisite?

Sí, habilitando Multisite en wp-config.php como WordPress tradicional. En WORDPRESS_CONFIG_EXTRA añade: define('WP_ALLOW_MULTISITE', true);. Luego Network Setup desde admin.

💡 Conclusión

WordPress Docker simplifica deployment masivamente: setup 5 minutos, backups triviales, múltiples sites fácil, updates sin miedo.

Recomendación según caso:

  • 🧪 Testing/desarrollo local: Método 1 (básico), puerto 8000, sin HTTPS
  • 🏢 Producción pequeña (1 site): Método 3 (Caddy HTTPS), backup cron diario
  • 🚀 Múltiples WordPress: Caddy reverse proxy + carpeta por site
  • Alto tráfico: Método 3 + Redis cache + PHP tuning + CDN

Próximos pasos:

  1. Setup WordPress Docker método que elijas
  2. Configurar .env con passwords fuertes
  3. Completar wizard WordPress (admin user)
  4. Instalar tema + plugins básicos
  5. Configurar backup automático (script cron)
  6. Si producción: setup HTTPS con Caddy/Let's Encrypt

¿Ya tienes WordPress corriendo en Docker? Comparte tu experiencia en comentarios.

Por ziru

0 0 votes
Article Rating
Subscribe
Notify of
guest
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Endika

That’s my boy, great job Optimus Prime

2
0
Would love your thoughts, please comment.x
()
x
El Diario IA
Resumen de privacidad

Esta web utiliza cookies para que podamos ofrecerte la mejor experiencia de usuario posible. La información de las cookies se almacena en tu navegador y realiza funciones tales como reconocerte cuando vuelves a nuestra web o ayudar a nuestro equipo a comprender qué secciones de la web encuentras más interesantes y útiles.