Publicando mis apuntes mediante jekyll + git

Es posible que algunos de vosotros hayáis aprovechado la oferta del pack de estudiante de GitHub y hayáis cogido un VPS en DigitalOcean (cogiendo la configuración más económica puedes disfrutar de un VPS sencillito gratis durante casi 2 años), pero la segunda parte es la más divertida: ¿Y ahora que narices hago yo con esto?

Una de las cosas que hago desde hace tiempo es tomar mis apuntes en formato Markdown, ya que con eso consigo

  1. Tenerlos en un formato fácilmente exportable para subir a internet
  2. Mediante un editor como atom puedo verlos renderizados en tiempo real
  3. Al contener trozos de código en ocasiones, poder tener syntax highlight en multitud de plataformas

Hasta el momento tenía una copia de los archivos .md en mi Dropbox (últimamente en mi Owncloud), y de vez en cuando tenía que andar exportando desde los .md a un .html, y luego subirlo mediante FTP a la carpeta correspondiente... Como veis, un trabajo bastante tedioso.

Be engineer. Be lazy

Gráfico

Como buenos ingenieros, tenemos que utilizar estas maravillas de la tecnología llamadas ordenadores, que fueron creados para que nosotros no tengamos que hacer precisamente esas tareas repetitivas.

Llegué incluso a crearme un script en bash que me automatizaba la generación de .html a partir de los .md, pero seguía faltando la parte de subir el HTML mediante FTP. Y ya lo ideal hubiera sido subir sólo los archivos que hubieran cambiado... Oh wait.

Eso suena a una tarea genial para git.

Git + Jekyll al rescate

Tras decidir que la mejor opción para manejar las subidas de archivos sería utilizando git, sólo me faltaba la automatización de la generación de los .html a partir de los .md de lado del servidor (por eso de ya puestos a ser vagos, lo somos del todo).

Después de echar un ojo a algunas soluciones de generación de código estático, finalmente me decidí por utilizar Jekyll, generalmente orientado a blogs, pero una de las bondades de su sistema de layouts es que, literalmente, te lo puedes montar para lo que te de la gana (ej: utilizando las categorías para las asignaturas).

Tras cacharrear un poco con Jekyll, encontrar un tema decente, adaptarlo a mis necesidades (y comprender que no hay que ejecutar jekyll serve permanentemente, solo jekyll build) faltaba la parte de configuración del repositorio git.

Empezamos

Disclaimer

Tened en cuenta que no soy un experto en git ni en sistemas Unix, así que voy a explicar simplemente cómo solucioné mi problema, siendo consciente de que evidentemente habrá mil y una soluciones mejores.
También se da por hecho que se tienen instaladas y configuradas las herramientas de git

Tras ese pequeño comentario, ahí va la primera sorpresa del post: No tendréis que montar uno, sino dos repositorios.
Ala, ahí lo dejo.

El motivo es el siguiente: Si inicializamos un repositorio git con git init, si estamos en la rama MASTER, al hacer push hacia él mediante git push origin master nos dará error, ya que al haberlo inicializado mediante git init git guardará una copia de trabajo activa junto al repositorio.
En otras palabras, que también dispondrás de una copia física de los archivos que contiene el repositorio.

Para que esto no suceda, tienes dos opciones:

  1. Cambiar de rama antes y después de hacer cada push (Evidentemente es una tontería)
  2. Crear el repositorio mediante git init --bare

Si creamos el repositorio marcándolo como bare, no dispondremos de esa copia física de los archivos (que en nuestro caso sería necesaria para poder enlazar a ellos), así que a priori tampoco parece demasiado buena opción, verdad?

La parte donde aparecen los comandos

Ahora voy a explicar paso a paso cómo terminé montando el servidor git:

Crear el usuario git

Accediendo mediante SSH al servidor, crearemos un nuevo usuario llamado git, le asignaremos una contraseña y le crearemos su directorio en /home

sudo useradd git
sudo passwd git

sudo mkdir /home/git
sudo chown -R git /home/git

Añadir las claves SSH

Tendremos que añadir nuestra clave SSH al archivo /home/git/.ssh/authorized_keys

Si no sabéis cómo hacerlo, recomiendo leer este tutorial en DigitalOcean que lo explica de maravilla

Creando el repositorio central

Una vez seamos capaces de acceder mediante SSH como el usuario git, crearemos un repositorio bare, es decir, sin copia física de los archivos. Por tanto, deberemos elegir donde lo ubicaremos (preferentemente no en la misma carpeta donde ubicaremos nuestro contenido público).

Por comodidad, yo lo he creado en /home/git/apuntes.git (nota, todos los comandos serán ejecutados desde el usuario git)

cd ~/
mkdir apuntes.git
cd apuntes.git/
git init --bare

Tras ejecutar estos comandos, podremos observar como ahora la carpeta apuntes.git contiene todos los archivos que en otros repositorios git habremos podido encontrar dentro de la carpeta .git.

Accediendo al repositorio desde nuestro ordenador

Para comprobar que lo hemos hecho correctamente, desde nuestro ordenador intentaremos clonar el repositorio:


git clone git@miservidor.com:/home/git/apuntes.git

Para evitar complicaciones a la hora de poner la ruta, he preferido poner el PATH completo.
Cómo podéis observar, después de poner miservidor.com, se pone un símbolo de : y la ruta completa al repo.

Si todo ha ido bien, deberíais recibir por consola un mensaje indicando que habéis clonado un repositorio vacío.
Si es así, enhorabuena!

Ahora sólo necesitaríais añadir un archivo en local (uno cualquiera, un hola.txt por ejemplo) y ejecutar

git add .
git commit -m 'First commit'
git push origin master

Y si no recibís ningún error significa que todo va según lo previsto.

Jekyll entra en acción

Tras instalar la gem de Jekyll (no explicaré aquí cómo instalar una gem ni cómo utilizar Jekyll, ya que no es el objetivo principal de este post), situaremos nuestro site jekyll en una carpeta de nuestra elección.

En mi caso, opté por únicamente gestionar la carpeta _posts, ya que estoy bastante contento con el tema, y no voy a tocar el resto de configuraciones. Así que de momento accederemos a nuestra carpeta posts (a modo de ejemplo utilizaré la ruta /var/apuntes/_posts)

Una vez situados en nuestra carpeta _posts, haremos (esta vez sí) git init, y añadiremos el repositorio central como remote:

git remote add origin /home/git/apuntes.git
git pull origin master

Si todo ha ido bien, deberíamos ver como ahora en nuestra carpeta _posts ha aparecido el archivo que hemos subido antes desde nuestro ordenador.

Ahora sólo quedaría generar el contenido desde nuestro ordenador, hacer commit y push hacia el servidor git, y desde la carpeta _posts ir haciendo git pull origin master cada vez que subamos algo, no? Y después evidentemente generar el contenido mediante jekyll build.

Algo que evidentemente no estamos dispuestos a hacer cada vez que hagamos un cambio

El poder de los scripts

Git dispone de una herramienta muy potente llamada hooks, que a modo de resumen, podríamos decir que son unos scripts que se ejecutan cuando suceden unas determinadas acciones en el repositorio.

Como en nuestro caso queremos ejecutar varias acciones cada vez que el repositorio reciba una actualización, utilizaremos el hook post-receive.

Para ello, accederemos al directorio hooks ubicado en /home/git/apuntes.git y crearemos un archivo llamado post-receive con el siguiente contenido:

#!/bin/sh

unset GIT_DIR
cd /var/apuntes/_posts
git pull origin master && cd /var/apuntes && jekyll build

Tras crearlo, le daremos permisos de ejecución mediante la instrucción

sudo chmod 755 /home/git/apuntes.git/hooks/post-receive

Y si con suerte todo ha funcionado correctamente, si hacemos un nuevo cambio desde nuestro ordenador, y hacemos push hacia el repositorio central, podremos ver como en la salida del comando git push nos aparece la generación de contenido estático por parte de Jekyll (útil también para detectar cualquier error)

El paso final

Ahora ya sólo queda configurar el acceso al sitio web.
Para ello únicamente tenemos que enlazar a /var/apuntes/_site/, y ya que hemos delegado la regeneración del contenido estático a jekyll, y automatizado la ejecución a cada vez que se reciba una nueva actualización, el contenido servido será siempre el último disponible.

Evidentemente, si se quiere mantener el contenido protegido no hay más que añadir una política restringida de acceso mediante .htaccess, pero tampoco es el objetivo principal de este post.

Espero que a alguien le sea útil este pequeño pupurri de cosas a priori no demasiado relacionadas entre si.