Cómo instalar Ghost CMS con Docker en Ubuntu 20.04

Ghost es una plataforma de blogs de código abierto que te ayuda a crear un blog de aspecto profesional. Se lanzó en 2013 como alternativa a WordPress porque se estaba volviendo demasiado complejo. Ghost está escrito en JavaScript y funciona con Node.js.

En este tutorial, exploraremos cómo instalar Ghost CMS utilizando Docker en un servidor con Ubuntu 20.04. También utilizaremos Nginx como proxy y el certificado SSL Let’s Encrypt para asegurar nuestra instalación.

Requisitos previos

  • Un servidor con Ubuntu 20.04.

  • Un usuario sudo no root.

  • Asegúrate de que todo está actualizado.

    $ sudo apt update 
    $ sudo apt upgrade
    

Paso 1 - Configurar el cortafuegos UFW

El primer paso es configurar el cortafuegos. Ubuntu viene con ufw (Uncomplicated Firewall) por defecto.

Comprueba si el cortafuegos se está ejecutando.

$ sudo ufw status

Deberías obtener la siguiente salida.

Status: inactive

Permite el puerto SSH para que el cortafuegos no rompa la conexión actual al activarlo.

$ sudo ufw allow OpenSSH

Permite también los puertos HTTP y HTTPS.

$ sudo ufw allow 80
$ sudo ufw allow 443

Habilita el cortafuegos

$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

Comprueba de nuevo el estado del cortafuegos.

$ sudo ufw status

Deberías ver una salida similar.

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
80                         ALLOW       Anywhere
443                        ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
80 (v6)                    ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)

Paso 2 - Instalar Certbot y obtener el certificado SSL

Antes de continuar, necesitamos instalar la herramienta Certbot e instalar un certificado SSL para nuestro dominio.

Para instalar Certbot, utilizaremos el instalador de paquetes Snapd. El repositorio oficial de Certbot ha quedado obsoleto y el paquete Certbot de Ubuntu tiene más de un año de antigüedad. Snapd siempre lleva la última versión estable de Certbot y deberías usarla. Afortunadamente, Ubuntu 20.04 viene con Snapd preinstalado.

Asegúrate de que tu versión de Snapd está actualizada.

$ sudo snap install core 
$ sudo snap refresh core

Elimina cualquier versión antigua de Certbot.

$ sudo apt remove certbot

Instala Certbot.

$ sudo snap install --classic certbot

Utiliza el siguiente comando para asegurarte de que el comando Certbot puede ejecutarse creando un enlace simbólico al directorio /usr/bin.

$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

Genera un certificado SSL.

$ sudo certbot certonly --standalone -d example.com

El comando anterior descargará un certificado en el directorio /etc/letsencrypt/live/example.com de tu servidor.

Paso 3 - Instalar Docker y Docker Compose

El primer paso es instalar el motor Docker y Docker Compose. Primero, desinstala cualquier versión antigua de Docker.

$ sudo apt remove docker docker-engine docker.io containerd runc

Instala algunos paquetes necesarios para que Docker funcione.

$ sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release

Añade la clave GPG oficial de Docker.

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Añade el repositorio oficial de Docker.

$ echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Actualiza los repositorios del sistema.

$ sudo apt update

Instala la última versión de Docker Engine.

$ sudo apt install docker-ce docker-ce-cli containerd.io

Comprueba que Docker Engine se está ejecutando e instalando correctamente.

$ sudo docker run hello-world

Por defecto, Docker requiere sudo para ejecutarse. Para evitarlo, podemos añadir la cuenta de usuario actual al grupo de usuarios docker.

$ sudo usermod -aG docker ${USER}

Para aplicar la nueva pertenencia al grupo, cierra la sesión y vuelve a iniciarla o utiliza el siguiente comando.

$ su - ${USER}

Ahora, puedes ejecutar los comandos de Docker sin usar sudo.

A continuación, descarga la versión estable actual de Docker compose.

sudo curl -L "https://github.com/docker/compose/releases/download/1.28.6/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

En el momento de escribir este tutorial, 1.28.6 es la última versión de Docker compose. Siempre puedes cambiar o elegir una versión diferente en el comando consultando desde la página de versiones de Github de Docker compose.

Aplica el permiso de ejecución a la versión instalada de Docker compose.

$ sudo chmod +x /usr/local/bin/docker-compose

Prueba la instalación.

$ docker-compose --version
docker-compose version 1.28.6, build 5db8d86f

Paso 4 - Instalar Ghost

La instalación de Ghost constará de tres componentes: el paquete Ghost, un servidor de bases de datos como MySQL y un servidor web (Nginx). Todos estos servicios pueden instalarse utilizando un único archivo Docker compose.

Crear un archivo Docker Compose

En primer lugar, crea un directorio para almacenar y lanzar tu archivo Docker Compose.

$ mkdir ghost && cd ghost

Crea un archivo llamado docker-compose.yml y ábrelo con el editor Nano.

$ nano docker-compose.yml

Pega el siguiente código en el archivo. Sustituye example.com por tu dominio e inserta una contraseña de base de datos en lugar del valor your_password. Mantén los valores de database__connection__password y MYSQL_ROOT_PASSWORD iguales. Sustituye <username> por el nombre de usuario de tu servidor.

version: '3.3'
services:

  ghost:
    image: ghost:latest
    restart: always
    depends_on:
      - db
    environment:
      url: https://example.com
      database__client: mysql
      database__connection__host: db
      database__connection__user: ghost
      database__connection__password: ghostdbpass
      database__connection__database: ghostdb
      mail__transport: SMTP
      mail__options__host: {Your Mail Service host}
      mail__options__port: {Your Mail Service port}
      mail__options__secureConnection: {true/false}
      mail__options__service: {Your Mail Service}
      mail__options__auth__user: {Your User Name}
      mail__options__auth__pass: {Your Password}
    volumes:
      - /home/<username>/ghost/content:/var/lib/ghost/content

  db:
    image: mariadb:latest
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: your_mysql_root_password
	  MYSQL_USER: ghost
      MYSQL_PASSWORD: ghostdbpass
      MYSQL_DATABASE: ghostdb
    volumes:
      - /home/<username>/ghost/mysql:/var/lib/mysql

  nginx:
    build:
      context: ./nginx
      dockerfile: Dockerfile
    restart: always
    depends_on:
      - ghost
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /etc/letsencrypt/:/etc/letsencrypt/
      - /usr/share/nginx/html:/usr/share/nginx/html

El archivo Docker compose crea unos puntos de montaje, es decir, mapea ciertos directorios del servidor a directorios dentro del contenedor.

  • Los directorios /var/lib/ghost/content y /var/lib/mysql dentro de tus contenedores se asignan a /home/<username>/ghost/content y /home/<username>/ghost/mysql en el servidor.
  • Nginx utiliza el enlace /etc/letsencrypt/ para acceder a los certificados de Let's Encrypt desde el servidor.
  • Nginx también necesita acceder al directorio de usuario /usr/share/nginx/html para poder acceder a los archivos de Let's Encrypt Challenge del certificado.

En el archivo anterior, también hemos incluido opciones para configurar el correo. Si utilizas un servicio de correo SMTP popular como Mailgun, Mailjet, Mandrill, Postmark, Sendgrid, SendCloud, SES, Zoho o Gmail, puedes añadir simplemente el nombre del servicio y tu nombre de usuario y contraseña SMTP y prescindir del resto de los campos. Si no, rellena todas las demás opciones y elimina el nombre del servicio y debería seguir funcionando. Puedes consultar más opciones de correo en la documentación de Ghost sobre Opciones de correo.

Crea directorios para todos los montajes de bind descritos anteriormente (excepto para /etc/letsencrypt, que ya estaba creado cuando creamos el certificado anteriormente)

$ cd ~/ghost
$ mkdir content
$ mkdir mysql
$ sudo mkdir -p /usr/share/nginx/html

Crea la imagen Docker de Nginx

El archivo Docker compose que hemos creado depende de la imagen Docker de Nginx. Para que funcione, tenemos que incluir un archivo de configuración personalizado para Nginx que funcione con Ghost.

Crea un directorio para esta imagen en el directorio actual.

$ mkdir nginx

Crea un archivo llamado Dockerfile en este directorio.

$ touch nginx/Dockerfile

Pega el siguiente código en el Dockerfile.

FROM nginx:latest
RUN rm /etc/nginx/conf.d/default.conf
COPY ghost.conf /etc/nginx/conf.d

El código anterior indica a Docker que utilice la última imagen de Nginx. También elimina el archivo de configuración de Nginx por defecto y copia el archivo de configuración personalizado que hemos creado para nuestro Ghost CMS.

Crea un archivo llamado ghost.conf en el directorio nginx.

$ touch nginx/ghost.conf

Pega el siguiente código en el archivo ghost.conf. Sustituye todas las instancias de example.com por tu dominio.

server {
  listen 80;
  listen [::]:80;
  server_name example.com;
  # Useful for Let's Encrypt
  location /.well-known/acme-challenge/ { root /usr/share/nginx/html; allow all; }
  location / { return 301 https://$server_name$request_uri; }
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name example.com;
    
  access_log /var/log/nginx/ghost.access.log;
  error_log /var/log/nginx/ghost.error.log;
  client_max_body_size 20m;

  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
  ssl_prefer_server_ciphers on;
  ssl_session_timeout 1d;
  ssl_session_cache shared:SSL:10m;

  ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

  location / {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://ghost:2368;
  }
}

La configuración anterior redirigirá todas las peticiones HTTP a HTTPS y servirá como proxy para que el servicio de Ghost lo sirva a través de tu dominio.

Paso 5 - Ejecuta el sitio

Ejecuta el siguiente comando desde el directorio ghost para iniciar el servicio Ghost.

$ docker-compose up -d

Ahora, puedes verificar tu instalación abriendo https://example.com en tu navegador web. El Docker puede tardar varios minutos en activar todos los servicios, por lo que es posible que tengas que actualizarlo si no ves tu blog de inmediato.

Página web de los fantasmas

Si tu sitio no aparece en el navegador, tienes que revisar los registros de Docker. Para ello, cierra primero tu contenedor.

$ cd ghost
$ docker-compose down

Ejecuta Docker compose en un estado adjunto para ver los registros generados por cada contenedor.

$ docker-compose up

Para cerrar el contenedor y volver al prompt de bash, pulsa CTRL+C. Una vez que hayas terminado de solucionar el problema, puedes volver a ejecutar el contenedor y tu blog debería ser visible esta vez.

Paso 6 - Completar la configuración

Para terminar de configurar tu blog Ghost, visita https://example.com/ghost en tu navegador. El extra /ghost al final del dominio de tu blog te redirige al Panel de Administración de Ghost o, en este caso, a la configuración, ya que estás accediendo a ella por primera vez.

Página de configuración del fantasma

Aquí tendrás que crear tu cuenta de administrador y elegir un título para el blog.

Detalles de la configuración del fantasma

También puedes invitar a otros miembros del personal o colaboradores para tu blog, lo que también puedes hacer más tarde si decides omitirlo ahora.

Página de invitación al personal fantasma

Al final de la configuración, aparecerá el panel de administración de Ghost.

Panel de administración de Ghost

Si quieres cambiar al modo oscuro, puedes hacerlo haciendo clic en el interruptor situado junto al botón del engranaje de configuración en la parte inferior de la página de configuración.

Activación del modo oscuro del fantasma

Ya verás algunas publicaciones por defecto que son básicamente guías para ayudarte a navegar y utilizar Ghost. Puedes despublicarlas o eliminarlas y empezar a publicar.

Paso 7 - Actualizar Ghost

En nuestro archivo de composición de Docker, estamos sacando la última versión de Ghost disponible en el momento de la instalación, lo que facilita la actualización de tu blog de Ghost.

Para actualizar, tienes que apagar tu contenedor, sacar las últimas imágenes y volver a ejecutar el contenedor.

$ docker-compose down
$ docker-compose pull && docker-compose up -d

Paso 8 - Renueva tu certificado SSL Let's Encrypt

Los certificados de Let's Encrypt sólo son válidos durante 90 días. Por lo tanto, necesitamos configurar un cronjob que renueve el certificado automáticamente.

Abre Crontab en tu editor.

$ sudo crontab -e

Pega la siguiente línea al final que ejecutará Certbot a las 11 de la noche todos los días. Sustituye example.com por tu dominio.

0 23 * * *   certbot certonly -n --webroot -w /usr/share/nginx/html -d example.com --deploy-hook='docker exec ghost_nginx_1 nginx -s reload'

Ejecutar a las 11 PM todos los días no significa que tu certificado se renovará todos los días, ya que Certbot renovará tu certificado sólo si su fecha de caducidad está dentro de los 30 días. Ejecutar esto cada noche da al script un número de oportunidades para intentarlo antes de la expiración.

El comando anterior también reiniciará el servidor Nginx dentro del contenedor Docker después de la renovación exitosa.

Puedes probar el cronjob utilizando la opción --dry-run de Certbot.

$ sudo bash -c "certbot certonly -n --webroot --dry-run -w /usr/share/nginx/html -d example.com --deploy-hook='docker exec ghost_nginx_1 nginx -s reload'"

Conclusión

Con esto concluye nuestro tutorial sobre cómo configurar Ghost CMS en tu servidor basado en Ubuntu 20.04 utilizando Docker. Si tienes alguna pregunta o algún comentario, compártelo en los comentarios de abajo.

También te podría gustar...