5 min read

Ghost CMS, Arquitectura e Implementación con Docker

Ghost CMS, Arquitectura e Implementación con Docker

Manual técnico completo para comprender, configurar y desplegar Ghost CMS en un entorno de producción usando contenedores Docker.

1. ¿Qué es Ghost CMS y cómo funciona?

Ghost es un sistema de gestión de contenidos (CMS) de código abierto (*Open Source*) de última generación, desarrollado sobre Node.js. Fue concebido como una alternativa ultrarrápida, ligera y centrada 100% en la publicación de contenidos, boletines informativos (newsletters) y modelos de membresía/suscripción.

Arquitectura y Componentes Clave

  • Backend (Node.js + Express):** Procesa las peticiones HTTP con altísima concurrencia y bajo consumo de memoria RAM.
  • ORM y Base de Datos (Bookshelf.js / Knex + MySQL 8):** Almacena de forma relacional y estructurada usuarios, entradas, configuraciones y etiquetas. En producción, Ghost exige el uso exclusivo de MySQL 8.0.
  • Capa de Renderizado Frontend (Handlebars .hbs):** Motor de plantillas dinámico que renderiza HTML en el servidor de forma instantánea.
  • Arquitectura Headless (Content API y Admin API):** Permite desacoplar el frontend para consumir el contenido desde aplicaciones móviles o frameworks modernos como Next.js, Nuxt o Astro.
  • Editor de Contenidos (Koenig Editor):** Guarda las entradas en formato estructurado JSON (MobileDoc/Lexical), asegurando la compatibilidad limpia entre web, emails y aplicaciones.

Enlaces Oficiales y Recursos

2. Requisitos Previos del Sistema

  • Servidor VPS con Linux (Ubuntu 22.04 LTS / 24.04 LTS recomendado).
  • Mínimo 1 GB de memoria RAM (2 GB recomendados para procesos de actualización).
  • Docker Engine y Docker Compose V2 instalados.
  • Un dominio o subdominio con un registro DNS tipo A apuntando a la IP pública del servidor.
  • Un Proxy Inverso (Nginx, Traefik o Caddy) para la terminación SSL (HTTPS).

3. Explicación Detallada de Variables de Entorno (.env)

A continuación se detallan todas las variables de entorno críticas necesarias para orquestar la pila de servicios en Docker:

Variable Tipo / Formato Descripción y Función Técnica
GHOST_URL URL (https://...) CRÍTICA. La URL pública exacta donde se servirá el sitio. Define cómo se forman las URLs absolutas, imágenes, etiquetas rel y cookies de sesión en el panel /ghost.
GHOST_PORT Puerto (ej. 2368) Puerto interno expuesto por la aplicación en el host para conectarse con el proxy inverso Nginx.
MYSQL_ROOT_PASSWORD Texto / Secreto Contraseña maestra del administrador de MySQL. Usada para crear la base de datos inicial y administrar el motor.
MYSQL_DATABASE Texto (ej. ghost_prod) Nombre de la base de datos relacional creada dentro del contenedor de MySQL.
MYSQL_USER Texto Usuario sin privilegios de root que utilizará el backend de Ghost para sus operaciones CRUD cotidianas.
MYSQL_PASSWORD Texto / Secreto Contraseña de acceso para el usuario limitado de Ghost en MySQL.
MAIL_HOST Hostname SMTP Servidor de salida SMTP (ej. smtp.mailgun.org, smtp.sendgrid.net) para correos transaccionales del sistema.
MAIL_PORT Puerto (ej. 587) Puerto de conexión SMTP. El puerto 587 usa STARTTLS y es el estándar de la industria.
MAIL_USER Usuario SMTP Nombre de usuario autenticado en la plataforma del proveedor de correo electrónico.
MAIL_PASS Contraseña / API Key Credencial de autenticación o token de la API SMTP.

4. Archivos de Configuración Completo

Creación de la Estructura de Trabajo en Bash

BASHTerminal
# Crear directorio del proyecto
mkdir -p /opt/ghost-docker
cd /opt/ghost-docker

1. Archivo de Variables de Entorno: .env

ENV.env
# =================================-------------------
# CONFIGURACIÓN GENERAL DE GHOST
# =================================-------------------
GHOST_URL=https://danielasbun.page
GHOST_PORT=2368

# =================================-------------------
# CONFIGURACIÓN DE BASE DE DATOS (MYSQL 8.0)
# =================================-------------------
MYSQL_ROOT_PASSWORD=SuperRootSecretPassword2026!
MYSQL_DATABASE=ghost_production
MYSQL_USER=ghost_db_user
MYSQL_PASSWORD=GhostUserSecretPassword2026!

# =================================-------------------
# CONFIGURACIÓN CORREO TRANSACCIONAL (SMTP)
# =================================-------------------
MAIL_HOST=smtp.mailgun.org
MAIL_PORT=587
MAIL_USER=postmaster@danielasbun.page
MAIL_PASS=3a8f192b0c9e123456789abcdef

2. Archivo de Orquestación: docker-compose.yml

YAMLdocker-compose.yml
version: '3.8'

services:
  db:
    image: mysql:8.0
    container_name: ghost_db
    restart: always
    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:
      - ghost_net

  ghost:
    image: ghost:5-alpine
    container_name: ghost_app
    restart: always
    depends_on:
      - db
    ports:
      - "127.0.0.1:${GHOST_PORT}:2368"
    environment:
      # URL pública
      url: ${GHOST_URL}
      
      # Conexión a Base de Datos
      database__client: mysql
      database__connection__host: db
      database__connection__user: ${MYSQL_USER}
      database__connection__password: ${MYSQL_PASSWORD}
      database__connection__database: ${MYSQL_DATABASE}
      
      # Configuración SMTP
      mail__transport: SMTP
      mail__options__host: ${MAIL_HOST}
      mail__options__port: ${MAIL_PORT}
      mail__options__auth__user: ${MAIL_USER}
      mail__options__auth__pass: ${MAIL_PASS}
    volumes:
      - ghost_content:/var/lib/ghost/content
    networks:
      - ghost_net

volumes:
  db_data:
  ghost_content:

networks:
  ghost_net:
    driver: bridge

3. Configuración del Proxy Inverso: Nginx (ghost.conf)

NGINX/etc/nginx/sites-available/ghost.conf
server {
    listen 80;
    server_name danielasbun.page;

    location / {
        proxy_pass http://127.0.0.1:2368;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

5. Paso a Paso para la Ejecución del Despliegue

Paso 1: Habilitar el sitio en Nginx y obtener Certificado SSL

BASHTerminal
# Enlazar sitio
sudo ln -s /etc/nginx/sites-available/ghost.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

# Obtener certificado SSL gratuito con Let's Encrypt / Certbot
sudo certbot --nginx -d danielasbun.page

Paso 2: Desplegar el Stack de Docker

BASHTerminal
# Iniciar los contenedores en segundo plano
cd /opt/ghost-docker
docker compose up -d

Paso 3: Verificación y Monitoreo

BASHTerminal
# Estado de los contenedores
docker compose ps

# Monitorear logs del inicio de Ghost
docker compose logs -f ghost

6. Mantenimiento y Comandos Útiles

  • Actualizar versión de Ghost:
    BASHTerminal
    docker compose pull
    docker compose up -d
  • Respaldo de Base de Datos:
    BASHTerminal
    docker exec ghost_db mysqldump -u root -p${MYSQL_ROOT_PASSWORD} ghost_production > backup_ghost.sql
  • Respaldo de Archivos e Imágenes: Copiar el contenido almacenado en el volumen persistente ghost_content.