Instalación de Ghost

Segundo post, aunque en realidad es el principio de esto.

Empezaremos por lo más natural, instalación y configuración del propio blog. Con esto tocaremos la parte de sistemas, mi preferida, aunque la parte creativa también aparecerá dentro de unos cuantos posts para mostrar cómo he tocado por encima el tema por defecto, obteniendo lo que estáis viendo ahora mismo.

Hemos seguido una de tantas guías para su instalación, en ésta vienen los pasos principales para configurar ghost junto con sus respectivas dependencias, una ubuntu, por ejemplo, el node.js y un servidor web ligero, en este caso nginx.

Para alojar este blog hemos elegido una ubuntu ya que debian lo considero demasiado salvaje, en el plan en el que yo lo uso en casa. Para algo más duradero prefiero que el propio sistema frene mis instintos actualizadores más básicos. En el momento de escribir este post tenemos una Ubuntu 14.04 corriendo bajo nuestros pies.

En la receta señalada anteriormente se nos muestran diferentes formas de asegurar nuestro servidor, no seré yo quien os diga aquí y ahora cuáles de las nombradas he elegido, ni cuáles más le he añadido, pero digamos que me parecen suficientes ya que este blog no es ningún archivo secreto de la NSA.

Una vez instalado el sistema y sus seguridades podemos entrar en faena. La pieza clave en todo esto es el servidor node.js y en Ubuntu tenemos una forma muy fácil de mantenernos al día gracias al PPA de Chris Lea, ejecutando las siguientes líneas podremos instalarlo sin problemas:

# apt-get install python-software-properties
# apt-add-repository ppa:chris-lea/node.js
Evented I/O for V8 javascript. Node's goal is to provide an easy way to build scalable network programs  
More info: https://launchpad.net/~chris-lea/+archive/ubuntu/node.js  
Press [ENTER] to continue or ctrl-c to cancel adding it

gpg: keyring `/tmp/tmpzzdhy1lt/secring.gpg' created  
gpg: keyring `/tmp/tmpzzdhy1lt/pubring.gpg' created  
gpg: requesting key C7917B12 from hkp server keyserver.ubuntu.com  
gpg: /tmp/tmpzzdhy1lt/trustdb.gpg: trustdb created  
gpg: key C7917B12: public key "Launchpad chrislea" imported  
gpg: Total number processed: 1  
gpg:               imported: 1  (RSA: 1)  
OK  
# apt-get update
# apt-get install nodejs

Si observáis, a mí no me gusta nada utilizar sudo, como ya habréis supuesto soy muy radical, prefiero un sudo su a tiempo más que una repetición de sudo's. Esto es herencia debianita pura, cuando empecé con ella creo que sudo ni siquiera existía, o al menos no era mainstream. Ya tenemos la primera piedra, sigamos.

Por mucho que me duela he configurado el blog con MySQL aunque prefiero PostgreSQL. Mirando por ahí parece ser que se suele usar mayormente el primero, ya veremos en el futuro si nos tiramos el rollo y hacemos una migración a nuestra base de datos de cabecera, pero por ahora:

# apt-get install mysql-client mysql-server

Durante la instalación nos pide un password para administrar el cluster, guardadlo en un lugar seguro.

Ya podemos entrar en la consola de administración para crear las bases de datos y los usuarios:

# mysql -uroot -p
Enter password: ********  
Welcome to the MySQL monitor.  Commands end with ; or \g.  
Your MySQL connection id is 42  
Server version: 5.5.37-0ubuntu0.14.04.1 (Ubuntu)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its  
affiliates. Other names may be trademarks of their respective  
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create database ghostdev;  
Query OK, 1 row affected (0.00 sec)

mysql> create database ghost;  
Query OK, 1 row affected (0.00 sec)

mysql> create user 'ghost'@'localhost' identified by 'YOUR_PASSWORD';  
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on ghost.* to 'ghost'@'localhost';  
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on ghostdev.* to 'ghost'@'localhost';  
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;  
Query OK, 0 rows affected (0.00 sec)

mysql> quit  
Bye  

Con esto tendremos una base de datos de producción y otra de desarrollo para las pruebas, así como sus usuarios correspondientes.

Saltamos al servidor web, el elegido en estos casos es el ligero nginx, que actuará como proxy de la aplicación ghost corriendo sobre node.js:

# apt-get install nginx

También creamos los directorios que albergarán todos los archivos de la aplicación:

# mkdir /var/cache/nginx
# chown www-data:www-data /var/cache/nginx
# mkdir /var/www
# chown www-data:www-data /var/www

Para el archivo de configuración de nuestro nginx, /etc/nginx/nginx.conf, hemos cogido el mismo que indicaba el artículo, aunque tendremos que cambiarlo un poco en el futuro, cuando tengamos soporte multi-idioma en ghost y pongamos en funcionamiento el dominio .org:

user www-data;  
worker_processes 4;  
pid /run/nginx.pid;

events {  
    worker_connections 768;
    # multi_accept on;
}

http {

    proxy_cache_path  /var/cache/nginx levels=1:2 keys_zone=one:8m max_size=3000m inactive=600m;
    proxy_temp_path /var/tmp;
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    gzip on;
    gzip_comp_level 6;
    gzip_vary on;
    gzip_min_length  1000;
    gzip_proxied any;
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    gzip_buffers 16 8k;

    upstream ghost_upstream {
      server 127.0.0.1:2368;
      keepalive 64;
    }

    server {
    listen 80;

    server_name libreadmin.es;

    if ($host = 'libreadmin.es' ) {
            rewrite  ^/(.*)$  http://www.libreadmin.es/$1  permanent;
    }

        location ~ ^/(ghost/signup/) {
                rewrite ^/(.*)$ http://libreadmin.es/ permanent;
        }

    location ~ ^/(img/|css/|lib/|vendor/|fonts/|robots.txt|humans.txt) {
      root /var/www/core/client/assets;
      access_log off;
      expires max;
    }

    location ~ ^/(shared/|built/) {
      root /var/www/core;
      access_log off;
      expires max;
    }

    location ~ ^/(favicon.ico) {
      root /var/www/core/shared;
      access_log off;
      expires max;
    }

    location ~ ^/(content/images/) {
      root /var/www;
      access_log off;
      expires max;
    }

    location / {
      proxy_redirect off;
      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;
      proxy_set_header   Host                   $http_host;
      proxy_set_header   X-NginX-Proxy    true;
      proxy_set_header   Connection "";
      proxy_http_version 1.1;
      proxy_cache one;
      proxy_cache_key ghost$request_uri$scheme;
      proxy_pass         http://ghost_upstream;
    }
    }

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Ya queda poco, prometido.

El meollo viene ahora, nos bajamos el archivo que contiene el propio ghost como indican en las instrucciones de instalación:

$ curl -L https://ghost.org/zip/ghost-latest.zip -o ghost.zip

Y lo descomprimimos en el directorio /var/www. Necesitaremos el paquete unzip y ejecutar unos comandos muy simples:

# unzip -uo ghost.zip -d /var/www

Los siguientes pasos son para desplegar la aplicación en sí, los ejecutamos desde el directorio /var/www, en donde hemos decomprimido el esqueleto de la aplicación:

# npm install --production
# npm install mysql
# npm install forever -g

Este último comando mantendrá la aplicación levantada en caso de que falle alguna vez.

Para cerrar el círculo debemos crear un script en el raíz de este directorio llamado starter.sh que se encargará de esta tarea junto con el paquete que acabamos de instalar, su contenido es el siguiente:

#!/bin/sh

if [ $(ps aux | grep node | grep -v grep | wc -l | tr -s "\n") -eq 0 ]  
then  
    export PATH=/usr/local/bin:$PATH
    export NODE_ENV=production
    NODE_ENV=production forever start --sourceDir /var/www index.js >> /var/log/nodelog.txt 2>&1
fi  

Debemos proporcionarle permisos de ejecución, como a todo buen script y terminamos de arreglar los permisos en el directorio para que el servidor web y la aplicación tomen posesión de sus dominios:

# chmod +x /var/www/starter.sh
# chown -R www-data:www-data /var/www/

Añadiremos una entrada en el cron para que el script se active con cada reinicio de la máquina, mediante el comando crontab -e, y eligiendo el editor que más nos guste, añadimos estas líneas al final:

# For Ghost
@reboot /var/www/starter.sh

Necesitamos crear un archivo de configuración propio de nuestra aplicación, si vemos el directorio donde hemos descomprimido ghost nos aparecerá un archivo de ejemplo config.example.js, le cambiamos el nombre a config.js, lo editamos y dejamos el archivo como sigue:

// # Ghost Configuration
// Setup your Ghost install for various environments

var path = require('path'),  
    config;

config = {  
    // ### Production
    // When running Ghost in the wild, use the production environment
    // Configure your URL and mail settings here
    production: {
        url: 'http://www.libreadmin.es',
        mail: {},
        database: {
            client: 'mysql',
            connection: {
                host: 'localhost',
                user: 'ghost',
                password: '********',
                database: 'ghost',
                charset: 'utf8'
            },
        },
        server: {
            // Host to be passed to node's `net.Server#listen()`
            host: '127.0.0.1',
            // Port to be passed to node's `net.Server#listen()`, for iisnode set this to `process.env.PORT`
            port: '2368'
        }
    }
};

// Export config
module.exports = config;  

Recordad que el usuario y el password deben ser los que habéis introducido en la configuración de las bases de datos de MySQL.

Y listo, con todo esto configurado ya podemos lanzar la aplicación:

# ./starter.sh

Nos dirigimos a la dirección web elegida y ya podremos entrar en nuestro nuevo y flamante blog para contar al mundo todas nuestras inquietudes.

Ah, y no olvidéis consultar la guía de uso de ghost.

Nota Importante: para aquellos que al dirigirse a su blog y se desilusionen con el mensaje Bad Gateway 502, un consejo, listad los procesos que maneja el paquete forever:

# forever list
info:    Forever processes running  
data:        uid  command         script   forever pid  logfile                 uptime  
data:    [0] EEAF /usr/bin/nodejs index.js 5510    5526 /root/.forever/EEAF.log 0:20:20:31.522  

Y si miráis dentro de ese log seguramente descubréis qué es lo que ocurre. En mi caso parece ser que ghost no tenía acceso a la base de datos, un reinicio arregló el problema. Gracias mil a uno de los usuarios que comentaron el post del que he sacado el material para este artículo.