> ## Content Index
> Fetch the complete content index at: https://blog.devutilites.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Ghost a fondo: qué es, cómo funciona y cómo instalarlo bien
- URL: https://blog.devutilites.com/que-es-ghost-y-como-instalarlo/
- Published: 2026-09-28T09:42:02.000Z
- Updated: 2026-09-28T12:41:30.000Z
- Description: El editor, los temas, las rutas, los miembros, las newsletters, la API y tres formas de instalarlo con copias y actualizaciones incluidas. Todo lo que hay que saber para publicar con Ghost en tu propio servidor.
- Author: Luis Collantes
- Tags: DevOps, Herramientas

Todos hemos pasado por ahí. Quieres escribir, solo escribir. Abres el panel de tu CMS y te recibe una pantalla con veintitrés avisos de actualización, un plugin que ha dejado de funcionar y un constructor visual que tarda más en cargar que tú en olvidar la idea que traías.

Ghost nació para acabar con eso. Este blog funciona con Ghost, instalado en mi propio servidor y con un tema hecho a medida. En este artículo te cuento qué es, cómo funciona por dentro, qué lo hace especial y cómo instalarlo **bien**: con correo, copias de seguridad y un plan para actualizar sin miedo.

## Qué es Ghost

Ghost es una plataforma de publicación de **código abierto**, pensada para blogs, revistas digitales y newsletters. Empezó en 2013 como un proyecto de John O'Nolan, que venía del mundo de WordPress y se hizo una pregunta incómoda: ¿y si un CMS se dedicara *solo* a publicar, y a hacerlo bien?

De esa pregunta salió un sistema escrito en **Node.js**, con licencia MIT. Lo desarrolla la Ghost Foundation, una organización sin ánimo de lucro, así que no hay inversores empujando para llenar el producto de funciones de relleno. Se financia con **Ghost(Pro)**, su servicio de alojamiento. Tú puedes usar ese servicio o **alojarlo tú mismo gratis**, que es lo que vamos a ver.

![Una caja de tipos de imprenta antigua con un periódico encima](https://blog.devutilites.com/content/images/2026/09/ghost-imprenta.jpg)

Ghost es, en el fondo, tu propia imprenta: escribes, maquetas y repartes. Foto: [Adam Jones from Kelowna, BC, Canada](https://commons.wikimedia.org/wiki/File:Handset%5FPress%5Fwith%5FCopy%5Fof%5FSan%5FDiego%5FUnion%5FNewspaper%5F-%5FSan%5FDiego%5FUnion%5FPrinting%5FOffice%5F-%5FOld%5FTown%5FSan%5FDiego%5FState%5FHistoric%5FPark%5F-%5FSan%5FDiego,%5FCA%5F-%5FUSA%5F%286930660491%29.jpg?ref=blog.devutilites.com), [CC BY-SA 2.0](https://creativecommons.org/licenses/by-sa/2.0?ref=blog.devutilites.com), vía Wikimedia Commons.

Ghost hace tres cosas, y las hace integradas:

- **Publicar:** un editor excelente, temas y un SEO bien resuelto de serie.
- **Construir audiencia:** tus lectores se suscriben y reciben cada artículo por correo.
- **Cobrar, si quieres:** suscripciones de pago con Stripe y contenido solo para miembros.

Las versiones recientes, las 6.x, han añadido además estadísticas de visitas propias y la integración con la "web social" mediante ActivityPub, para que otras plataformas como Mastodon puedan seguir tu publicación.

## Cómo está hecho por dentro

Entender las piezas te ahorrará muchos dolores de cabeza al instalarlo y al hacer copias:

![Esquema de Ghost: lectores, editor y scripts entran por un proxy HTTPS hacia el proceso de Ghost, que usa MySQL, la carpeta content y servicios externos](https://blog.devutilites.com/content/images/2026/09/ghost-arquitectura.png)

Un proceso de Node, una base de datos y una carpeta: eso es Ghost. Diagrama: devutilites.

- **Un único proceso de Node.js** sirve a la vez la web pública, el panel de administración en `/ghost`, las APIs y el sistema de miembros. Escucha en el puerto 2368.
- **MySQL 8** guarda los artículos, las etiquetas, los miembros y los ajustes. SQLite solo se usa para desarrollo.
- **La carpeta `content/`** guarda las imágenes que subes, los temas, y ficheros como `routes.yaml` o `redirects.yaml`.
- **Un proxy inverso** delante (Caddy, Nginx o Traefik) pone el HTTPS.
- **Servicios externos:** SMTP para los correos de acceso, Mailgun para las newsletters masivas y Stripe para los pagos. Todos son opcionales.

La configuración se lee de `config.production.json` o de **variables de entorno**, donde cada nivel del JSON se separa con dos guiones bajos. `database.connection.host` se convierte en `database__connection__host`. Es lo que usaremos con Docker.

💡

Una idea clave: **todo lo que haces en el panel usa la misma Admin API** que puedes usar tú desde tus propios scripts. No hay funciones "secretas" solo para el panel.

## El editor

El editor de Ghost es limpio y rápido, y esconde mucha potencia detrás de una sola tecla: `/`. Escríbela en una línea vacía y aparece un menú de **tarjetas**:

- **Contenido:** imágenes, galerías, vídeo, audio, archivos para descargar, bloques de código con resaltado.
- **Estructura:** avisos destacados (*callouts*), desplegables (*toggles*), separadores, cabeceras y botones.
- **Enlaces con vista previa (bookmarks):** pegas una URL y Ghost crea una tarjeta con el título, la descripción y la imagen de esa página.
- **Miembros:** formularios de suscripción y el bloque **Public preview**, que marca dónde acaba la parte pública de un artículo.
- **Escape:** tarjetas de Markdown y de HTML para cuando necesitas algo que el editor no hace.

Si vienes de Markdown, también funcionan sus atajos: `#` para títulos, `-` para listas, `>` para citas y tres comillas invertidas para un bloque de código. Y hay más detalles que se agradecen:

- **Fragmentos (snippets):** guardas un bloque (una firma, un aviso, una llamada a la acción) y lo reutilizas en cualquier artículo.
- **Historial:** Ghost guarda versiones del artículo mientras escribes y puedes recuperar una anterior.
- **Vista previa y enlace privado:** puedes compartir un borrador con alguien para que lo revise antes de publicar.
- **Programación:** eliges fecha y hora de publicación, y si se envía por correo.
- **Ajustes por artículo:** URL, extracto, imagen para redes sociales, título y descripción para buscadores, URL canónica e incluso código propio en la cabecera.

## Organizar el contenido

Ghost tiene un modelo sencillo: **artículos** (con fecha, van al listado) y **páginas** (estáticas, como "Sobre mí"). Todo se organiza con **etiquetas**, y hay dos detalles que conviene conocer:

- **La primera etiqueta es la principal (primary tag).** Los temas la usan para las migas de pan, los colores o los artículos relacionados. En este blog, la etiqueta principal es el tema del artículo.
- **Las etiquetas internas empiezan por `#`.** No se muestran al público, pero sirven para filtrar: por ejemplo `#destacado-portada` para elegir qué sale en un bloque concreto.

Cada etiqueta puede tener su descripción, su imagen y su color, y tiene su propia página (`/tag/nombre/`) con su propio feed RSS.

## Temas: cómo se ve tu publicación

Un tema de Ghost es una carpeta con plantillas **Handlebars**, CSS y JavaScript, y un `package.json` con su configuración. Las plantillas son HTML con "huecos" que Ghost rellena:

```handlebars
{{!-- Fragmento de index.hbs: lista de artículos --}}
{{#foreach posts}}
  <article class="card">
    <a href="{{url}}">
      {{#if feature_image}}
        <img src="{{img_url feature_image size="m"}}" alt="{{title}}">
      {{/if}}
      <h2>{{title}}</h2>
      <p>{{excerpt words="30"}}</p>
      <time datetime="{{date format="YYYY-MM-DD"}}">{{date format="DD MMM YYYY"}}</time>
    </a>
  </article>
{{/foreach}}

{{!-- En cualquier plantilla: los 3 últimos de un tema --}}
{{#get "posts" filter="tag:devops" limit="3"}}
  {{#foreach posts}}<a href="{{url}}">{{title}}</a>{{/foreach}}
{{/get}}
```

Algunas cosas que hacen que trabajar con temas sea agradable:

- **Ajustes personalizados:** en el `package.json` defines opciones (colores, tipografías, cuántas secciones mostrar…) que luego aparecen en **Ajustes → Diseño** para cambiarlas sin tocar código.
- **Imágenes adaptables:** defines tamaños en el tema y Ghost genera versiones más pequeñas de cada imagen automáticamente.
- **Validación:** la herramienta `gscan` revisa tu tema y te avisa de errores antes de subirlo.
- **Traducciones:** los textos del tema se pueden traducir con ficheros de idioma.

### Rutas: la parte que casi nadie conoce

El fichero `routes.yaml` decide **qué contenido vive en cada dirección**, y el tema decide cómo se ve. Es lo que permite, por ejemplo, la página de temas de este blog, que no existe en el editor:

![Tabla que relaciona cada URL con la regla de routes.yaml y la plantilla del tema que la pinta](https://blog.devutilites.com/content/images/2026/09/ghost-rutas.png)

Cómo decide Ghost qué plantilla usar para cada dirección. Diagrama: devutilites.

Con él puedes crear rutas propias, tener varias **colecciones** (por ejemplo, separar los tutoriales del resto) o cambiar la estructura de las URL:

```yaml
routes:
  /temas/:
    template: temas          # una página que no existe en el editor

collections:
  /tutoriales/:
    permalink: /tutoriales/{slug}/
    filter: tag:tutorial     # los artículos con esta etiqueta viven aquí
    template: index
  /:
    permalink: /{slug}/      # todo lo demás, en la portada
    template: index

taxonomies:
  tag: /tag/{slug}/
  author: /author/{slug}/
```

Se sube desde **Ajustes → Labs → Rutas**. Un aviso: un artículo solo puede pertenecer a **una** colección. Si cambias las colecciones, cambian las URL, así que acompáñalo de redirecciones.

## Miembros, newsletters y pagos

Esta es la gran baza de Ghost: la relación con tus lectores está integrada, sin plugins ni servicios de terceros para lo básico.

![Recorrido de visitante a miembro gratuito y a miembro de pago, con Portal y los niveles de visibilidad de los artículos](https://blog.devutilites.com/content/images/2026/09/ghost-miembros.png)

Los niveles de acceso y quién ve cada artículo. Diagrama: devutilites.

- **Altas sin contraseña:** el lector escribe su correo y recibe un **enlace mágico** para entrar. Nada de contraseñas que olvidar.
- **Portal:** la ventana de alta, acceso y gestión de cuenta la pone Ghost en cualquier tema. Los botones solo tienen que enlazar a `#/portal/signup`.
- **Varias newsletters:** puedes tener, por ejemplo, una semanal y otra de novedades, y cada lector elige las que quiere.
- **Planes de pago (tiers):** con Stripe conectado, creas planes mensuales o anuales y decides qué artículos son para cada uno.
- **Comentarios nativos:** solo para miembros, lo que corta el spam de raíz.
- **Estadísticas:** aperturas y clics de cada envío, altas por artículo y de dónde vienen.

![Una pila de periódicos doblados](https://blog.devutilites.com/content/images/2026/09/ghost-periodicos.jpg)

Cada artículo puede llegar también por correo a tus suscriptores. Foto: [Bernerlover](https://commons.wikimedia.org/wiki/File:Vecteezy%5Fstack-of-newspaper%5F1961329.jpg?ref=blog.devutilites.com), [CC BY 4.0](https://creativecommons.org/licenses/by/4.0?ref=blog.devutilites.com), vía Wikimedia Commons.

⚠️

**Ojo con el correo en una instalación propia.** Ghost usa dos tipos de envío: los **correos de acceso y alta** (se configuran con cualquier SMTP) y las **newsletters masivas**, que en una instalación propia necesitan una cuenta de **Mailgun**. Sin Mailgun puedes tener miembros, pero no enviarles los artículos por correo.

## SEO y rendimiento

Ghost se encarga de casi todo lo que en otros sitios necesita un plugin:

- **Metadatos** de título y descripción, y etiquetas para redes sociales (Open Graph y X/Twitter), editables por artículo.
- **Datos estructurados** (JSON-LD) para que los buscadores entiendan qué es un artículo, quién lo firma y cuándo se publicó.
- **Mapa del sitio** en `/sitemap.xml` y **RSS** en `/rss/`, generados solos.
- **URL canónicas**, para cuando publicas algo que ya salió en otro sitio.
- **Páginas ligeras:** Ghost no carga nada que tu tema no pida.

Si cambias URLs, las **redirecciones** se gestionan con un `redirects.yaml` que se sube también desde **Ajustes → Labs**. Admite expresiones regulares:

```yaml
301:
  /blog/(.*): /$1                # quita un prefijo antiguo
  /como-instalar-ghost/: /que-es-ghost-y-como-instalarlo/

302:
  /directo/: https://www.youtube.com/@tucanal
```

## La API: Ghost como pieza de tu sistema

Ghost tiene dos APIs:

- **Content API:** de solo lectura, para mostrar tu contenido en otra web o app. Usa una clave pública.
- **Admin API:** para crear, editar y publicar. Usa una clave secreta y tokens JWT de corta duración.

Las claves se obtienen creando una **integración personalizada** en **Ajustes → Integraciones**. Con la Content API, sacar los tres últimos artículos es una línea:

```bash
curl -s "https://blog.tudominio.com/ghost/api/content/posts/?key=TU_CLAVE_DE_CONTENIDO&limit=3&fields=title,url,published_at" \
  | jq '.posts[] | {title, url}' 
```

Y con la Admin API, la librería oficial de Node se encarga de firmar los tokens por ti:

```javascript
// npm install @tryghost/admin-api
const GhostAdminAPI = require('@tryghost/admin-api');

const api = new GhostAdminAPI({
  url: 'https://blog.tudominio.com',
  key: process.env.GHOST_ADMIN_KEY,   // "id:secreto" de la integración
  version: 'v6.0'
});

// Crea un borrador a partir de HTML
const post = await api.posts.add(
  {
    title: 'Hola desde la API',
    html: '<p>Este borrador lo ha creado un script.</p>',
    tags: ['DevOps'],
    status: 'draft'
  },
  { source: 'html' }
);

console.log('Borrador creado:', post.url);
```

Las integraciones también pueden tener **webhooks**: Ghost avisa a una URL cuando se publica un artículo, se da de alta un miembro, etc. Con eso puedes regenerar una web estática, avisar en Telegram o lanzar cualquier automatización. Y si quieres llevarlo al extremo, puedes usar Ghost **sin cabeza** (*headless*): solo como panel y API, con tu frontend en Next.js, Astro o lo que prefieras.

## Cómo instalarlo

Te enseño tres caminos, del más cómodo al más artesanal. Para cualquiera de ellos necesitas:

- Un servidor Linux. Con 1 GB de RAM funciona; con 2 GB vas holgado, sobre todo si MySQL está en la misma máquina.
- Un dominio o subdominio apuntando a la IP del servidor.
- **MySQL 8** en producción.
- Si vas a tener miembros: un SMTP para los correos de acceso y, para newsletters, Mailgun.

### Opción 1: con Coolify, en un par de clics

Si ya usas Coolify, es la vía más rápida y es como funciona este blog:

1. Crea un proyecto y pulsa **\+ New → Service**.
2. Busca **Ghost** en la lista de plantillas.
3. Pon tu dominio en la configuración del servicio. Coolify se encarga del certificado HTTPS.
4. Revisa las variables de entorno: la versión de la imagen, la URL y, si lo necesitas, el correo.
5. Pulsa **Deploy**.

Coolify levanta Ghost y MySQL, y te los deja conectados. Una recomendación: **fija la versión mayor** de la imagen (`ghost:6-alpine`) en lugar de `latest`, para que una versión nueva no te sorprenda un día cualquiera.

### Opción 2: con Docker Compose y Caddy

Para tener control total sin complicarte. Crea una carpeta con este `docker-compose.yml`:

```yaml
services:
  ghost:
    image: ghost:6-alpine
    restart: always
    ports:
      - "127.0.0.1:2368:2368"
    environment:
      url: https://blog.tudominio.com
      database__client: mysql
      database__connection__host: db
      database__connection__user: ghost
      database__connection__password: ${DB_PASSWORD}
      database__connection__database: ghost
      # Correos de acceso y altas (no son las newsletters)
      mail__transport: SMTP
      mail__from: "Mi blog <hola@tudominio.com>"
      mail__options__host: smtp.tuproveedor.com
      mail__options__port: 587
      mail__options__auth__user: ${SMTP_USER}
      mail__options__auth__pass: ${SMTP_PASSWORD}
    volumes:
      - ghost_content:/var/lib/ghost/content
    depends_on:
      db:
        condition: service_healthy

  db:
    image: mysql:8.0
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MYSQL_DATABASE: ghost
      MYSQL_USER: ghost
      MYSQL_PASSWORD: ${DB_PASSWORD}
    volumes:
      - ghost_db:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1"]
      interval: 10s
      retries: 10

volumes:
  ghost_content:
  ghost_db:
```

Las contraseñas van en un fichero `.env` en la misma carpeta, que Docker Compose lee automáticamente:

```bash
# .env junto al docker-compose.yml (no lo subas a Git)
DB_PASSWORD=una-contraseña-larga-y-aleatoria
DB_ROOT_PASSWORD=otra-contraseña-distinta
SMTP_USER=usuario-smtp
SMTP_PASSWORD=contraseña-smtp
```

Fíjate en dos detalles: Ghost escucha solo en `127.0.0.1`, así que nadie puede llegar a él saltándose el proxy; y espera a que MySQL esté **sano** antes de arrancar, lo que evita errores en el primer arranque. Arráncalo con `docker compose up -d` y ponle delante **Caddy**, que consigue y renueva el certificado solo:

```text
blog.tudominio.com {
    encode zstd gzip
    reverse_proxy 127.0.0.1:2368
}

# Redirige www al dominio principal
www.blog.tudominio.com {
    redir https://blog.tudominio.com{uri} permanent
}
```

### Opción 3: la instalación clásica con Ghost-CLI

Es el método tradicional, en un servidor Ubuntu con Nginx, MySQL y una versión de Node.js compatible con tu versión de Ghost (la documentación oficial indica cuál). Ghost-CLI hace casi todo por ti:

```bash
sudo npm install ghost-cli@latest -g

sudo mkdir -p /var/www/ghost
sudo chown $USER:$USER /var/www/ghost
sudo chmod 775 /var/www/ghost
cd /var/www/ghost

ghost install          # asistente: URL, MySQL, Nginx, SSL y servicio
```

El asistente pregunta la URL y los datos de MySQL, configura Nginx, pide el certificado SSL y crea un servicio de systemd. Para el día a día, estos son los comandos que más uso:

```bash
ghost ls               # instancias y su estado
ghost log              # registros (añade -e para ver solo errores)
ghost doctor           # comprueba permisos, versiones y configuración
ghost restart
ghost update           # actualiza a la última versión
ghost update --rollback  # vuelve a la anterior si algo falla
```

## Los primeros pasos

Con Ghost en marcha, entra en `https://blog.tudominio.com/ghost` y crea tu cuenta de administrador. Después:

1. **Ajustes → General:** título, descripción, idioma de la publicación y zona horaria.
2. **Ajustes → Diseño:** elige un tema o sube el tuyo, y ajusta sus opciones.
3. **Ajustes → Navegación:** el menú principal y el del pie.
4. **Etiquetas:** crea tus temas con descripción y color.
5. **Ajustes → Miembros:** decide si quieres suscripciones, quién puede darse de alta y si hay planes de pago.
6. **Correo:** en los ajustes de newsletter y correo, configura el remitente y comprueba que llegan los correos de acceso.
7. Borra el contenido de ejemplo, escribe tu primer artículo y pulsa **Publicar**.

## Copias de seguridad y actualizaciones

Una instalación de Ghost son **dos cosas que copiar**: la base de datos y la carpeta `content`. La exportación JSON de **Ajustes → Labs** es útil para migrar, pero no incluye las imágenes ni los temas, así que no te fíes solo de ella. Este script hace las dos copias y conserva las últimas catorce:

```bash
#!/bin/sh
# copia-ghost.sh: base de datos + carpeta content, con fecha
set -e
FECHA=$(date +%F)
DESTINO=/root/copias/ghost
mkdir -p "$DESTINO"

docker compose exec -T db sh -c 'mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" --single-transaction ghost' \
  | gzip > "$DESTINO/ghost-db-$FECHA.sql.gz"

# El nombre del volumen depende de la carpeta del proyecto: compruébalo con docker volume ls
docker run --rm -v ghost_ghost_content:/content:ro -v "$DESTINO":/copias alpine \
  tar czf "/copias/ghost-content-$FECHA.tar.gz" -C /content .

# Conserva solo las últimas 14 copias de cada tipo
ls -1t "$DESTINO"/ghost-db-*.sql.gz | tail -n +15 | xargs -r rm
ls -1t "$DESTINO"/ghost-content-*.tar.gz | tail -n +15 | xargs -r rm
```

Prográmalo con cron cada noche y, sobre todo, **saca las copias del servidor**: a otro servidor, a un almacenamiento S3 o a casa.

Para actualizar, el orden importa. Al arrancar una versión nueva, Ghost **migra la base de datos**, y ese paso no tiene vuelta atrás sin una copia:

```bash
./copia-ghost.sh                 # primero, siempre, la copia
docker compose pull ghost        # descarga la última 6.x
docker compose up -d ghost       # arranca y migra la base de datos
docker compose logs -f ghost     # espera a ver "Ghost booted"
```

Dentro de la misma versión mayor (6.x), las actualizaciones suelen ser tranquilas. Para saltar de versión mayor, lee antes las notas de la versión: a veces cambian requisitos como la versión de Node o de MySQL.

## Problemas comunes y su causa

| Síntoma                                     | Causa más probable                                                                                              |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| **ERR\_TOO\_MANY\_REDIRECTS**               | Cloudflare con la nube naranja y el SSL en modo Flexible, o la url de Ghost con http cuando se entra por https. |
| **Imágenes rotas o enlaces a otro dominio** | La variable url no coincide con el dominio real.                                                                |
| **Error 413 al subir imágenes o temas**     | El proxy limita el tamaño de subida (en Nginx, client\_max\_body\_size).                                        |
| **No llegan los correos de acceso**         | Falta la configuración SMTP o el remitente no está autorizado en el proveedor.                                  |
| **No se pueden enviar newsletters**         | No hay cuenta de Mailgun configurada.                                                                           |
| **Error 503 justo después de actualizar**   | Ghost está migrando la base de datos. Espera y mira los registros.                                              |
| **El tema no se puede activar**             | Tiene errores. Pásale gscan y corrígelos.                                                                       |

## Dos consejos que me habría gustado saber antes

**Si usas Cloudflare, cuidado con el modo SSL.** Con el proxy activado (la nube naranja) y el SSL en modo *Flexible*, Cloudflare le habla a tu servidor por HTTP, tu servidor le redirige a HTTPS, y así hasta el infinito. El navegador acaba mostrando `ERR_TOO_MANY_REDIRECTS`. La solución es poner el SSL en **Full (strict)**, o dejar el registro DNS en gris. Hablo por experiencia: me pasó con este mismo blog.

**Haz la primera copia de seguridad antes de escribir el primer artículo.** Es el momento en que menos te duele configurarlo y en el que más te lo agradecerás después.

## En resumen

Ghost es lo que pasa cuando alguien se toma en serio la tarea de publicar. Por fuera, un editor que no se interpone. Por dentro, una arquitectura sencilla: un proceso de Node, una base de datos y una carpeta. Y alrededor, todo lo que en otros sitios necesita diez plugins: newsletters, suscripciones, SEO y una API completa.

Si tienes algo que contar y quieres una herramienta que no te robe el tiempo, pruébalo. Y si te animas a instalarlo y te atascas, ya sabes dónde encontrarme.