Instalar WordPress en Docker: Guía Completa con SSL y Nginx 2025

📋 TL;DR

Aprende a instalar WordPress en Docker con Nginx como reverse proxy y certificados SSL automáticos con Let’s Encrypt. Esta guía completa te lleva desde cero hasta producción con un stack profesional, backups automáticos y alta disponibilidad.

Lo que conseguirás:

  • ✅ WordPress funcionando en Docker con aislamiento total
  • ✅ SSL automático con renovación cada 90 días
  • ✅ Nginx optimizado como reverse proxy con caché
  • ✅ Scripts de backup y restauración funcionales
  • ✅ Stack listo para producción con healthchecks

Tiempo de lectura: ~25 minutos | Nivel: Intermedio

📚 Tabla de Contenidos

  1. Introducción
  2. ¿Por qué WordPress en Docker?
  3. Arquitectura del Stack
  4. Requisitos Previos
  5. Instalación Paso a Paso
  6. Configuración de SSL con Let’s Encrypt
  7. Configuración Avanzada
  8. Backups Automáticos
  9. Seguridad y Hardening
  10. Troubleshooting Común
  11. Comparativa con Alternativas
  12. Preguntas Frecuentes
  13. Conclusión y Próximos Pasos

> 📅 Última actualización: Diciembre 2025

> ✅ Verificado con: WordPress 6.4, Docker 24.0, Nginx 1.25, MySQL-guia-completa-tutorial-2025/) 8.0

> 🔄 Próxima revisión: Marzo 2026

Introducción {#introduccion}

WordPress sigue siendo el CMS más popular del mundo, con más del 40% de todos los sitios web. Sin embargo, la instalación tradicional (LAMP/LEMP stack) tiene limitaciones: dependencias del sistema, dificultad para actualizar, y complicaciones al escalar.

El problema: Instalar WordPress directamente en el servidor significa que cada actualización puede romper dependencias, los backups son complejos, y mover el sitio a otro servidor requiere reconfigurar todo desde cero.

La solución: Docker containeriza WordPress, MySQL y Nginx en contenedores aislados. Con Docker Compose, defines todo el stack en un archivo YAML y lo levantas con un solo comando. Añade Nginx como reverse proxy para manejar SSL automáticamente y obtienes un stack profesional listo para producción.

En esta guía completa aprenderás:

  • Cómo crear un stack WordPress completo con Docker Compose
  • Configurar Nginx como reverse proxy con SSL/TLS
  • Obtener y renovar certificados SSL automáticamente con Let’s Encrypt
  • Implementar backups automáticos y restauraciones
  • Hardening de seguridad para producción
  • Troubleshooting de problemas comunes

Ya seas sysadmin, desarrollador o entusiasta de homelab, esta guía te dará un WordPress self-hosted profesional y escalable.

Imagen 1

¿Por qué WordPress en Docker? {#por-que-docker}

Ventajas de Docker vs Instalación Tradicional

Aislamiento total: Cada servicio (WordPress, MySQL, Nginx) corre en su propio contenedor, evitando conflictos de versiones PHP, dependencias del sistema, o problemas de permisos.

Portabilidad: El mismo docker-compose.yml funciona en cualquier servidor con Docker, sin importar si es Ubuntu, Debian, CentOS o incluso Windows Server. Mueve tu WordPress completo copiando una carpeta.

Escalabilidad: Fácil escalar horizontalmente añadiendo más contenedores WordPress detrás de un load balancer. Cada instancia es idéntica y reproducible.

Backups simples: Los volúmenes Docker se pueden respaldar fácilmente. Restaurar es tan simple como copiar carpetas y levantar contenedores.

Actualizaciones seguras: Actualizar WordPress es docker compose pull && docker compose up -d. Si algo falla, vuelves atrás en segundos.

SSL automático: Con Nginx y Certbot, obtienes certificados SSL gratuitos que se renuevan automáticamente cada 90 días.

Cuándo NO usar Docker

  • Hosting compartido: Docker requiere acceso root y control del servidor
  • Recursos muy limitados: Docker añade overhead mínimo pero existe (RAM, CPU)
  • Aprendizaje inicial: Si nunca has usado Docker, hay curva de aprendizaje

Para homelabs, servidores dedicados, o VPS, Docker es la mejor opción.

Arquitectura del Stack {#arquitectura}

Nuestro stack consta de 4 servicios principales:

TEXT
┌─────────────────────────────────────────┐
│         Internet (HTTPS)                │
└──────────────┬──────────────────────────┘
               │
               ▼
┌─────────────────────────────────────────┐
│      Nginx (Reverse Proxy)              │
│      - Puerto 80 (HTTP → HTTPS)         │
│      - Puerto 443 (HTTPS)               │
│      - SSL/TLS (Let's Encrypt)          │
│      - Caché estático                   │
└──────────────┬──────────────────────────┘
               │
               ▼
┌─────────────────────────────────────────┐
│      WordPress Container                │
│      - Puerto 8080 (interno)            │
│      - PHP-FPM 8.2                      │
│      - wp-content (volumen persistente) │
└──────────────┬──────────────────────────┘
               │
               ▼
┌─────────────────────────────────────────┐
│      MySQL 8.0 Container                │
│      - Puerto 3306 (interno)            │
│      - Base de datos (volumen)          │
└─────────────────────────────────────────┘

Componentes:

  1. Nginx: Reverse proxy que maneja SSL/TLS, redirige HTTP a HTTPS, y cachea archivos estáticos
  2. WordPress: Contenedor oficial con PHP-FPM, conecta a MySQL vía red Docker
  3. MySQL: Base de datos persistente en volumen Docker
  4. Certbot: Contenedor que renueva certificados SSL automáticamente

Red Docker: Todos los contenedores están en la misma red wordpress_network, permitiendo comunicación interna sin exponer puertos al host.

Volúmenes:

  • wp_data: Archivos WordPress (themes, plugins, uploads)
  • db_data: Base de datos MySQL
  • certbot_data: Certificados SSL
  • certbot_www: Archivos de validación Let’s Encrypt

Requisitos Previos {#requisitos}

Software Necesario

  • Docker: Versión 20.10 o superior
  • Docker Compose: Versión 2.0 o superior (incluido con Docker Desktop)
  • Dominio: Opcional pero recomendado para SSL (puedes usar IP para pruebas)

Verificar Instalación

BASH
# Verificar Docker
docker --version
# Docker version 24.0.0, build abc123

# Verificar Docker Compose
docker compose version
# Docker Compose version v2.20.0

Puertos Requeridos

  • 80: HTTP (redirige a HTTPS)
  • 443: HTTPS (WordPress con SSL)

Verifica que estos puertos estén libres:

BASH
sudo netstat -tulpn | grep -E ':(80|443)'

Si están en uso, detén el servicio o cambia los puertos en docker-compose.yml.

DNS (Opcional pero Recomendado)

Para SSL con Let’s Encrypt, necesitas un dominio apuntando a tu servidor:

BASH
# Verificar DNS
dig tudominio.com +short
# Debe devolver la IP de tu servidor

Instalación Paso a Paso {#instalacion}

Paso 1: Crear Estructura de Directorios

BASH
mkdir -p ~/wordpress-docker
cd ~/wordpress-docker
mkdir -p nginx scripts

Paso 2: Configurar Variables de Entorno

Crea el archivo .env:

BASH
cat > .env << 'EOF'
# Base de datos
DB_NAME=wordpress
DB_USER=wp_user
DB_PASSWORD=Cambiar_Por_Password_Seguro_123!
MYSQL_ROOT_PASSWORD=Cambiar_Root_Password_Seguro_456!
TABLE_PREFIX=wp_

# Dominio
DOMAIN=tudominio.com
EMAIL=admin@tudominio.com

# WordPress
WORDPRESS_DEBUG=false
WORDPRESS_DEBUG_LOG=false
WORDPRESS_DEBUG_DISPLAY=false

# SSL
LETSENCRYPT_EMAIL=admin@tudominio.com
EOF

⚠️ IMPORTANTE: Cambia los passwords por defecto antes de iniciar. Genera passwords seguros:

BASH
openssl rand -base64 32

Paso 3: Docker Compose Completo

Crea docker-compose.yml:

YAML
version: '3.8'

services:
  wordpress:
    image: wordpress:6.4-php8.2-apache
    container_name: wordpress
    restart: unless-stopped
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: ${DB_USER}
      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
      WORDPRESS_DB_NAME: ${DB_NAME}
      WORDPRESS_TABLE_PREFIX: ${TABLE_PREFIX}
    volumes:
      - wp_data:/var/www/html
      - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
    depends_on:
      db:
        condition: service_healthy
    networks:
      - wordpress_network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/wp-admin/install.php"]
      interval: 30s
      timeout: 10s
      retries: 3

  db:
    image: mysql:8.0
    container_name: wordpress_db
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - wordpress_network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
      interval: 10s
      timeout: 5s
      retries: 5

  nginx:
    image: nginx:alpine
    container_name: wordpress_nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/wordpress.conf:/etc/nginx/conf.d/wordpress.conf:ro
      - certbot_data:/etc/letsencrypt
      - certbot_www:/var/www/certbot
    depends_on:
      - wordpress
    networks:
      - wordpress_network
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"

  certbot:
    image: certbot/certbot
    container_name: wordpress_certbot
    volumes:
      - certbot_data:/etc/letsencrypt
      - certbot_www:/var/www/certbot
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

volumes:
  wp_data:
    driver: local
  db_data:
    driver: local
  certbot_data:
    driver: local
  certbot_www:
    driver: local

networks:
  wordpress_network:
    driver: bridge

Paso 4: Configuración Nginx Principal

Crea nginx/nginx.conf:

NGINX
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    client_max_body_size 64M;

    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml text/javascript 
               application/json application/javascript application/xml+rss 
               application/rss+xml font/truetype font/opentype 
               application/vnd.ms-fontobject image/svg+xml;

    include /etc/nginx/conf.d/*.conf;
}

Paso 5: Configuración WordPress + SSL

Crea nginx/wordpress.conf (reemplaza tudominio.com con tu dominio):

NGINX
# Redirección HTTP → HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name tudominio.com www.tudominio.com;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

# Servidor HTTPS
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name tudominio.com www.tudominio.com;

    # SSL Configuration (se configurará después con Certbot)
    ssl_certificate /etc/letsencrypt/live/tudominio.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/tudominio.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # Security Headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    # Root y logs
    root /var/www/html;
    index index.php index.html index.htm;

    access_log /var/log/nginx/wordpress_access.log;
    error_log /var/log/nginx/wordpress_error.log;

    # WordPress
    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    # PHP-FPM
    location ~ \.php$ {
        fastcgi_pass wordpress:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_read_timeout 300;
    }

    # Cache estático
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # Denegar acceso a archivos sensibles
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }

    location ~* /(?:uploads|files)/.*\.php$ {
        deny all;
    }
}

Paso 6: Configuración PHP

Crea uploads.ini:

INI
file_uploads = On
memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300
max_input_time = 300

Paso 7: Iniciar el Stack

BASH
# Levantar contenedores
docker compose up -d

# Verificar que están corriendo
docker ps

# Ver logs
docker compose logs -f

Espera 30-60 segundos a que MySQL esté listo. Verifica los logs:

BASH
docker logs wordpress_db | grep "ready for connections"

Paso 8: Acceder a WordPress

Abre tu navegador en http://tu-ip o http://tudominio.com y completa la instalación de WordPress.

Imagen 2

Configuración de SSL con Let’s Encrypt {#ssl}

Obtener Certificado SSL

Una vez que WordPress está funcionando, obtén el certificado SSL:

BASH
docker compose exec certbot certbot certonly \
    --webroot \
    --webroot-path=/var/www/certbot \
    --email admin@tudominio.com \
    --agree-tos \
    --no-eff-email \
    -d tudominio.com \
    -d www.tudominio.com

Requisitos:

  • Dominio apuntando a tu servidor (DNS configurado)
  • Puerto 80 accesible desde internet
  • WordPress funcionando en HTTP

Renovación Automática

El contenedor certbot renueva automáticamente los certificados cada 12 horas. Si queda menos de 30 días para expirar, se renueva.

Para verificar renovación manual:

BASH
docker compose exec certbot certbot renew --dry-run

Reiniciar Nginx

Después de obtener el certificado, reinicia Nginx:

BASH
docker compose restart nginx

Ahora accede a https://tudominio.com y deberías ver el candado verde.

Configuración Avanzada {#configuracion-avanzada}

Optimización de Rendimiento

Caché en WordPress:

Instala un plugin de caché como WP Super Cache o W3 Total Cache. Esto reduce la carga del servidor significativamente.

OPcache en PHP:

Añade a uploads.ini:

INI
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000

Límites de Recursos:

Ajusta recursos en docker-compose.yml:

YAML
wordpress:
  deploy:
    resources:
      limits:
        cpus: '2'
        memory: 2G
      reservations:
        cpus: '1'
        memory: 1G

Variables de Entorno Adicionales

Añade a .env:

BASH
# WordPress
WORDPRESS_DEBUG=false
WORDPRESS_DEBUG_LOG=false
WORDPRESS_DEBUG_DISPLAY=false

# Performance
PHP_MEMORY_LIMIT=256M
PHP_MAX_EXECUTION_TIME=300

Múltiples Sitios WordPress

Para múltiples sitios, crea un stack por sitio o usa Nginx Proxy Manager (ver artículo relacionado).

Backups Automáticos {#backups}

Script de Backup

Crea scripts/backup.sh:

BASH
#!/bin/bash
set -e

BACKUP_DIR="${BACKUP_DIR:-/backups/wordpress}"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="wordpress_backup_${DATE}"

if [ -f .env ]; then
    export $(cat .env | grep -v '^#' | xargs)
fi

mkdir -p "${BACKUP_DIR}/${BACKUP_NAME}"

echo "📦 Respaldando base de datos..."
docker exec wordpress_db mysqldump \
    -u root \
    -p"${MYSQL_ROOT_PASSWORD}" \
    --all-databases \
    --single-transaction \
    --quick \
    --lock-tables=false \
    > "${BACKUP_DIR}/${BACKUP_NAME}/database.sql"

echo "📁 Respaldando archivos WordPress..."
docker run --rm \
    --volumes-from wordpress \
    -v "${BACKUP_DIR}/${BACKUP_NAME}":/backup \
    alpine tar czf /backup/wordpress_files.tar.gz -C /var/www/html .

cd "${BACKUP_DIR}"
tar czf "${BACKUP_NAME}.tar.gz" "${BACKUP_NAME}"
rm -rf "${BACKUP_NAME}"

# Eliminar backups antiguos (>7 días)
find "${BACKUP_DIR}" -name "*.tar.gz" -mtime +7 -delete

echo "✅ Backup completado: ${BACKUP_NAME}.tar.gz"

Hazlo ejecutable:

BASH
chmod +x scripts/backup.sh

Backup Manual

BASH
./scripts/backup.sh

Backup Automático (Cron)

Añade a crontab:

BASH
crontab -e

Añade esta línea (backup diario a las 2 AM):

TEXT
0 2 * * * cd /ruta/a/wordpress-docker && ./scripts/backup.sh >> /var/log/wordpress_backup.log 2>&1

Restaurar desde Backup

Crea scripts/restore.sh:

BASH
#!/bin/bash
set -e

if [ -z "$1" ]; then
    echo "Uso: $0 <archivo_backup.tar.gz>"
    exit 1
fi

BACKUP_FILE="$1"
TEMP_DIR=$(mktemp -d)
trap "rm -rf ${TEMP_DIR}" EXIT

if [ -f .env ]; then
    export $(cat .env | grep -v '^#' | xargs)
fi

tar xzf "${BACKUP_FILE}" -C "${TEMP_DIR}"
BACKUP_NAME=$(basename "${BACKUP_FILE}" .tar.gz)

echo "⚠️  ADVERTENCIA: Esta operación sobrescribirá los datos actuales"
read -p "¿Continuar? (s/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Ss]$ ]]; then
    exit 1
fi

echo "🗄️ Restaurando base de datos..."
docker exec -i wordpress_db mysql \
    -u root \
    -p"${MYSQL_ROOT_PASSWORD}" \
    < "${TEMP_DIR}/${BACKUP_NAME}/database.sql"

echo "📁 Restaurando archivos WordPress..."
docker run --rm \
    --volumes-from wordpress \
    -v "${TEMP_DIR}/${BACKUP_NAME}":/backup \
    alpine sh -c "cd /var/www/html && rm -rf * && tar xzf /backup/wordpress_files.tar.gz"

docker exec wordpress chown -R www-data:www-data /var/www/html
docker exec wordpress chmod -R 755 /var/www/html

echo "✅ Restauración completada"

Hazlo ejecutable:

BASH
chmod +x scripts/restore.sh

Uso:

BASH
./scripts/restore.sh /backups/wordpress/wordpress_backup_20251205_120000.tar.gz
Imagen 3

Seguridad y Hardening {#seguridad}

Firewall

Bloquea todos los puertos excepto 80 y 443:

BASH
# UFW (Ubuntu/Debian)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Secrets Management

NUNCA hardcodees passwords en docker-compose.yml. Usa archivo .env y añádelo a .gitignore:

BASH
echo ".env" >> .gitignore

Actualizaciones Automáticas

Usa Watchtower para actualizar contenedores automáticamente:

YAML
watchtower:
  image: containrrr/watchtower
  volumes:
    - /var/run/docker.sock:/var/run/docker.sock
  command: --interval 86400 --cleanup

Hardening WordPress

  1. Cambiar WP_DEBUG a false en producción (ya configurado en .env)
  1. Instalar plugin de seguridad: Wordfence o Sucuri Security
  1. Limitar intentos de login: Plugin «Limit Login Attempts Reloaded»
  1. Deshabilitar editor de archivos: Añade a wp-config.php:
PHP
define('DISALLOW_FILE_EDIT', true);
  1. Cambiar prefijo de tablas: Ya configurado con TABLE_PREFIX en .env
  1. Usar passwords fuertes: Genera con openssl rand -base64 32

Security Headers

Ya configurados en nginx/wordpress.conf:

  • Strict-Transport-Security: Fuerza HTTPS
  • X-Frame-Options: Previene clickjacking
  • X-Content-Type-Options: Previene MIME sniffing
  • X-XSS-Protection: Protección XSS básica

Troubleshooting Común {#troubleshooting}

Error: «Error establishing database connection»

Causa: WordPress no puede conectar a MySQL.

Solución:

  1. Verificar que MySQL está corriendo:
BASH
docker ps | grep db
  1. Verificar variables de entorno:
BASH
docker exec wordpress env | grep WORDPRESS_DB
  1. Verificar red Docker:
BASH
docker network inspect wordpress_network
  1. Probar conexión manual:
BASH
docker exec wordpress_db mysql -u root -p

Error: «Permission denied» en wp-content

Causa: Permisos incorrectos en volúmenes.

Solución:

BASH
docker exec wordpress chown -R www-data:www-data /var/www/html
docker exec wordpress chmod -R 755 /var/www/html

SSL no funciona / Certificado no se renueva

Causa: Certbot no puede validar dominio o renovación falla.

Solución:

  1. Verificar DNS:
BASH
dig tudominio.com
  1. Verificar puerto 80 accesible desde internet
  1. Verificar logs:
BASH
docker logs wordpress_certbot
  1. Renovar manualmente:
BASH
docker compose exec certbot certbot renew --force-renewal

WordPress muy lento

Causa: Falta de caché, PHP mal configurado, o recursos insuficientes.

Solución:

  1. Instalar plugin de caché (WP Super Cache, W3 Total Cache)
  1. Aumentar memoria PHP en uploads.ini:
INI
memory_limit = 512M
  1. Aumentar recursos Docker:
BASH
docker update --memory=2g wordpress
  1. Habilitar OPcache (ver sección Configuración Avanzada)

Error: «Maximum upload file size exceeded»

Causa: Límites de PHP o Nginx muy bajos.

Solución:

  1. Aumentar en uploads.ini:
INI
upload_max_filesize = 128M
post_max_size = 128M
  1. Aumentar en Nginx (nginx/wordpress.conf):
NGINX
client_max_body_size 128M;
  1. Reiniciar contenedores:
BASH
docker compose restart
Imagen 4

Comparativa con Alternativas {#comparativa}

WordPress en Docker vs Instalación Tradicional

CriterioDockerTradicional
Aislamiento✅ Total❌ Comparte sistema
Portabilidad✅ Mismo código en cualquier servidor❌ Depende del sistema
Backups✅ Copiar volúmenes⚠️ Scripts complejos
Actualizacionesdocker compose pull⚠️ Manual, puede romper
Escalabilidad✅ Horizontal fácil❌ Vertical solo
Curva aprendizaje⚠️ Requiere Docker✅ Más familiar
Rendimiento✅ Similar✅ Similar

Nginx vs Apache

CriterioNginxApache
Rendimiento✅ Mejor con alta concurrencia⚠️ Más pesado
Memoria✅ Muy eficiente⚠️ Más consumo
Configuración⚠️ Sintaxis propia✅ .htaccess familiar
SSL✅ Terminación SSL nativa✅ Soporte completo
Recomendado paraReverse proxy, alta cargaWordPress tradicional

MySQL vs MariaDB

CriterioMySQLMariaDB
Licencia⚠️ Oracle (GPL con restricciones)✅ Completamente open source
Rendimiento✅ Excelente✅ Excelente (fork de MySQL)
Compatibilidad✅ Estándar✅ 100% compatible con MySQL
RecomendadoProducción enterpriseHomelab, proyectos open source
Para este stack, usamos MySQL 8.0 por ser el estándar, pero puedes cambiar a MariaDB sin problemas. —

Preguntas Frecuentes {#faq}

¿Puedo usar otro dominio después de configurar?

Sí, pero necesitas:

  1. Actualizar DOMAIN en .env
  2. Actualizar server_name en nginx/wordpress.conf
  3. Obtener nuevo certificado SSL con Certbot
  4. Actualizar WP_HOME y WP_SITEURL en WordPress (Settings → General)

¿Cómo actualizo WordPress?

BASH
docker compose pull wordpress
docker compose up -d wordpress

Los datos en volúmenes se mantienen intactos.

¿Funciona con plugins de WordPress?

Sí, todos los plugins funcionan normalmente. Algunos plugins que requieren acceso al sistema (como algunos de backup) pueden necesitar configuración adicional.

¿Cuánta RAM necesito?

Mínimo recomendado:

  • 2GB: Para desarrollo/testing
  • 4GB: Para producción con tráfico bajo (<1000 visitas/día)
  • 8GB+: Para producción con tráfico medio-alto

¿Puedo usar este stack en producción?

Sí, este stack está listo para producción con:

  • Healthchecks en todos los servicios
  • Restart policies (unless-stopped)
  • SSL automático
  • Backups programables
  • Security headers configurados

Añade monitoring (Prometheus/Grafana) y logs centralizados para producción enterprise.

¿Cómo cambio el puerto de WordPress?

Edita docker-compose.yml:

YAML
nginx:
  ports:
    - "8080:80"  # Cambiar 80 por 8080
    - "8443:443" # Cambiar 443 por 8443

¿Puedo usar múltiples sitios WordPress?

Sí, dos opciones:

  1. Stack separado por sitio: Crea una carpeta por sitio con su propio docker-compose.yml
  2. Nginx Proxy Manager: Usa Nginx Proxy Manager para gestionar múltiples sitios desde una UI

¿Cómo accedo a la base de datos directamente?

BASH
docker exec -it wordpress_db mysql -u root -p

O desde fuera del contenedor (si expones el puerto):

YAML
db:
  ports:
    - "3306:3306"  # Solo para desarrollo, NO en producción

¿Los backups incluyen los certificados SSL?

No, los certificados SSL se renuevan automáticamente. Si quieres respaldarlos:

BASH
docker run --rm \
  --volumes-from wordpress_nginx \
  -v $(pwd)/backup:/backup \
  alpine tar czf /backup/ssl_certs.tar.gz -C /etc/letsencrypt .

¿Puedo usar Cloudflare con este stack?

Sí, pero configura Cloudflare en modo «Full (strict)» para mantener SSL end-to-end. El certificado SSL seguirá siendo necesario en el servidor.

¿Cómo migro un WordPress existente a Docker?

  1. Exporta base de datos del WordPress antiguo
  2. Copia carpeta wp-content completa
  3. Restaura base de datos en el nuevo stack
  4. Copia wp-content al volumen Docker
  5. Actualiza URLs en base de datos (usar plugin «Better Search Replace»)

¿Qué pasa si el contenedor se cae?

Con restart: unless-stopped, Docker reinicia automáticamente el contenedor. Para monitoreo, usa herramientas como Uptime Kuma o Prometheus.

¿Puedo usar este stack sin dominio (solo IP)?

Sí, pero sin SSL. Comenta las líneas SSL en nginx/wordpress.conf y accede por HTTP. Para SSL necesitas un dominio válido.

¿Cómo veo los logs de WordPress?

BASH
# Logs de WordPress
docker logs wordpress -f

# Logs de Nginx
docker logs wordpress_nginx -f

# Logs de MySQL
docker logs wordpress_db -f

¿Puedo usar este stack con Kubernetes?

Sí, pero necesitas convertir docker-compose.yml a manifiestos Kubernetes (Deployments, Services, Ingress). Considera usar Kompose para conversión automática.

Conclusión y Próximos Pasos {#conclusion}

Has configurado un stack WordPress profesional en Docker con Nginx y SSL automático. Tienes:

  • ✅ WordPress aislado y portable
  • ✅ SSL/TLS con renovación automática
  • ✅ Backups programables
  • ✅ Stack listo para producción

Próximos Pasos

  1. Instalar plugins esenciales:

– Caché: WP Super Cache o W3 Total Cache

– Seguridad: Wordfence o Sucuri

– SEO: Yoast SEO o Rank Math

  1. Configurar monitoring:

Prometheus + Grafana-loki-stack-de-observabilidad-completo-para-tu-homelab-2025/) para métricas

– Uptime Kuma para disponibilidad

  1. Optimizar rendimiento:

– CDN (Cloudflare)

– Caché de objetos (Redis)

– Optimización de imágenes

  1. Aprender más:

Docker Compose: De 0 a Homelab Completo

Nginx Proxy Manager: Reverse Proxy con UI

Portainer: Gestiona Docker con Interfaz Web

📦 Descargar Ejemplos

Todos los archivos de este tutorial están disponibles en GitHub:

🔗 Ver ejemplos en GitHub

Incluye:

  • docker-compose.yml completo
  • Configuraciones Nginx
  • Scripts de backup/restauración
  • Template .env
  • README con instrucciones

Artículos Relacionados

¿Has instalado WordPress en Docker con éxito? Comparte tu experiencia en los comentarios. Si tienes dudas sobre configuración avanzada o troubleshooting, pregunta y te ayudo.

¡Feliz self-hosting! 🚀

Por ziru

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
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.