Ir al contenido
  1. Posts/

Despliegue automatizado de tu web

··1384 palabras·7 mins
Felipe Torres González
Autor
Felipe Torres González
Tabla de contenido

Introducción
#

En esta entrada, explicaré cómo lograr un despliegue automatizado tras un cambio en un sitio web creado con Hugo y desplegado en Ubuntu Server con Apache gracias a Webhook.

Existen muchos servicios de hosting que permiten desplegar gratuitamente una página web creada con Hugo. Esto ya se explica en la documentación oficial. Para la mayoría, usar un servicio de hosting externo es la mejor opción, pero ¿qué ocurre si ya tienes un servidor?

Mi plan era alojar mi sitio web personal en mi propio servidor: Nubecita. Este servidor utiliza Ubuntu Server 24.04 y Apache como servidor web. Una de las combinaciones más comunes para alojar contenido en internet. Además, tengo mi sitio web subido a un repositorio en GitHub. Mi objetivo era automatizar el proceso de despliegue, de modo que cada vez que subo un nuevo cambio al repositorio, se implemente en el servidor web de producción.

Esta guía está diseñada para este tipo de configuración. Espero que a alguien le resulte útil.

Empezando por el principio
#

Antes de empezar a configurar los servicios y escribir los scripts, configuraremos nuestro sistema. Necesitaremos instalar Webhook. Optaré por la versión empaquetada de los repositorios, en lugar de la de la Snap Store:

sudo apt install webhook

Actualización: Necesitarás Webhook >= 2.8.2, ya que esa versión incluye todos los cambios necesarios para ejecutarse con Systemd.

Además, no recomiendo usar Hugo de la Snap Store, ya que te obligaría a tener tus scripts de despliegue en un directorio del sistema en lugar de tu directorio personal. Sin embargo, la decisión es tuya; ten en cuenta que no puedes usar Hugo de la Snap Store para seguir esta guía.

Script de deployment básico
#

Una vez que tengamos nuestro sistema listo, podemos comenzar con la parte interesante. Necesitaremos un script de despliegue, que no es más que un script que automatiza todos los pasos que realizarías si hicieras un despliegue manual. Para esta guía, incluiré el script que utilizo, pero tendrás que modificarlo según tus necesidades.

#!/bin/bash

echo "Retrieve new content from the repo..."
git clone https://github.com/felipet/personal-site.git --depth 1
cd personal-site
echo "Build the static page"
hugo
cd public
echo "Deploy the new content"
rsync -r ./ /var/www/html/felipe-site
chown -R www-data:www-data /var/www/html/felipe-site
systemctl reload apache2
echo "Wiping temporal data..."
cd ../../
rm -rf personal-site

Aspectos destacables del script:

  • Añade --depth 1 al comando clone. Esto ahorrará tiempo si tu repositorio contiene una cantidad considerable de imágenes y otros archivos pesados.

  • Tras sincronizar con rsync, cambio el propietario de los nuevos datos. El usuario www-data se usa con frecuencia en implementaciones de Apache. Considera si este usuario y grupo son la mejor opción para tu implementación.

  • Reinicio el servicio apache2 después de la implementación, por lo que este script debe ser ejecutado por un usuario con privilegios.

Puedes colocar el script donde quieras. Yo elegí la ruta /var/scripts y asigné como propietario del directorio al usuario y grupo www-data. Pruébalo y asegúrate de que funciona correctamente.

Configura el Webhook
#

Nuestro script de despliegue ya está listo, pero ¿cómo lo ponemos en práctica? Aquí es donde entra en juego Webhook. Añadiremos un nuevo servicio Systemd para gestionar Webhook y escribiremos el archivo de configuración que le indicará a Webhook qué webhook debe desplegarse para nuestro propósito.

Ejecutando Webhook como un servicio de Systemd
#

Configuraremos Webhook para que se ejecute como un servicio de Systemd. Esto se explica detalladamente en la documentación oficial, así que solo mencionaré las pequeñas modificaciones que realicé.

En resumen, este es el descriptor del socket:

[Unit]
Description=Webhook server socket

[Socket]
## Listen on one specific interface only
ListenStream=127.0.0.1:9191

[Install]
WantedBy=multi-user.target

Como puedes ver, indiqué que el socket solo escuchará las solicitudes provenientes de la dirección local. Planeo usar un proxy inverso, lo que añade una capa adicional de seguridad, ya que no quiero exponerlo al público. Si decides prescindir del proxy inverso, tendrás que escuchar en 0.0.0.0:9191, pero recuerda que necesitarás configurar una capa de seguridad adicional.

Y el descriptor del servicio:

[Unit]
Description=Webhook server

[Service]
Type=exec
ExecStart=/usr/bin/webhook -nopanic -hooks /var/webhooks/hooks.json -verbose -port 9191
StandardOutput=append:/var/log/webhook
StandardError=append:/var/log/webhook
User=root
Group=root

Muy importante: El puerto de escucha y el puerto que se pasa como argumento al Webhook deben ser el mismo. Puede parecer un consejo básico, pero si no se utilizan los puertos estándar, es posible que se omita la especificación de algún puerto, lo que puede provocar una pérdida de tiempo.

Como ya mencioné, es necesario ejecutar este servicio como root para tener los privilegios suficientes para ejecutar systemctl reload apache2.

Configura un nuevo Webhook
#

Quizás hayas notado que pasamos como argumento al Webhook el archivo /var/webhooks/hooks.json. Ahora, analizaremos este archivo.

Elegí la ruta /var/webhooks, pero puedes ubicarla donde prefieras. También le di permisos de lectura y escritura a www-data en esa ruta, ya que mi objetivo es desplegar mi repositorio allí cada vez que se llame al servicio.

Este es el contenido del archivo hooks.json:

[
    {
        "id": "deploy_felipe_site",
        "execute-command": "/var/scripts/deploy_felipe-site.bash",
        "command-working-directory": "/var/webhooks",
        "trigger-rule":
        {
            "match":
            {
                "type": "payload-hmac-sha256",
                "secret": "SOME_SECRET_STRING!!!",
                "parameter":
                {
                    "source": "header",
                    "name": "X-Hub-Signature-256"
                }
            }
        }
    }
]

El valor de execute-command debe ser la ruta a tu script de despliegue. Los valores del campo match se explican en la documentación oficial de GitHub. No olvides reemplazar el valor de secret. Genera una cadena segura aleatoria e insértala. Guárdala por un tiempo, ya que necesitarás introducir la cadena secreta al configurar nuestro Webhook en GitHub.

Para terminar
#

¿Listo para empezar? Entonces ejecuta estos comandos:

sudo systemctl enable webhook.socket
sudo systemctl start webhook.socket

Y comprueba que todo funciona correctamente:

systemctl status webhook.socket

Deberías obtener algo similar a este resultado:

● webhook.socket - Webhook server socket
     Loaded: loaded (/etc/systemd/system/webhook.socket; enabled; preset: enabled)
     Active: active (listening) since Tue 2025-01-14 10:39:37 UTC; 6s ago
   Triggers: ● webhook.service
     Listen: 127.0.0.1:9191 (Stream)
      Tasks: 0 (limit: 37781)
     Memory: 8.0K (peak: 256.0K)
        CPU: 820us
     CGroup: /system.slice/webhook.socket

Jan 14 10:39:37 nubecita.eu systemd[1]: Listening on webhook.socket - Webhook server socket.

Configura Apache como un proxy inverso
#

Aquí, puede que te desvíes del camino que seguí. Si no te gusta usar un proxy inverso, abre directamente un puerto en tu firewall y ofrece tu servicio al público. En ese caso, te recomiendo que sigas la documentación de Webhook para habilitar HTTPS.

Yo uso Apache para alojar varios sitios web y como proxy inverso para algunos servicios web que ofrezco. Para mí, fue la elección obvia. Evito abrir otro puerto en mi firewall y Apache se encarga de la gestión de SSL, una situación ideal.

Para reenviar las solicitudes al socket de Webhook, añade un nuevo host virtual con el comando ProxyPass:

ProxyPass /webhook http://127.0.0.1:9191/hooks
ProxyPassReverse /webhook http://127.0.0.1:9191/hooks

Esto redirigirá una solicitud a https://nubecita.eu/webhook/deploy_felipe_site al socket Webhook local. Si creó un nuevo host virtual, habilítelo. En cualquier caso, reinicie el servicio Apache.

sudo systemctl reload apache2

Nuestro backend ya está listo, hagamos una solicitud sencilla para comprobar que responde. ¡Crucemos los dedos!

Podemos usar Curl para enviar una solicitud POST al endpoint donde instalamos nuestro webhook:

curl -X 'POST' \
  'https://nubecita.eu/webhook/deploy_felipe_site'
Hook rules were not satisfied.%

Como no enviamos nuestras credenciales ni ninguna otra información con la solicitud, nuestro servicio nos indica que no cumplimos con las reglas definidas en hooks.json. Perfecto, nuestro backend responde y bloquea las solicitudes ficticias. Completemos el proceso de implementación con el último paso.

Crea un webhook en GitHub
#

Hemos llegado al último paso necesario. Debemos configurar un webhook en nuestro repositorio de GitHub.

El proceso se explica en esta página (https://docs.github.com/en/webhooks/using-webhooks/creating-webhooks). Sin embargo, resumamos los pasos:

  1. Ve a la sección de configuración del repositorio que contiene el contenido de tu sitio web.
  2. Abre Webhooks en el panel izquierdo y haz clic en «Añadir webhook».
  3. Introduce la URL de tu endpoint en «URL de carga útil» y selecciona «application/json» como «Tipo de contenido».
  4. ¿Recuerdas la cadena secreta? Ahora es el momento de usarla de nuevo. Añádela en el campo «Secreto».
  5. Por supuesto, activa la verificación SSL.
  6. Finalmente, elige cuándo quieres que se ejecute el webhook. Yo seleccioné «Envíos» y «Lanzamientos».

Guárdalo y ve a la pestaña «Entregas recientes». Verás que se ha iniciado una comprobación de estado. Si se ha realizado correctamente, ¡enhorabuena! El proceso de despliegue está listo.

Realiza cualquier cambio en el contenido del repositorio y envíalo. Verás que los cambios se han desplegado en tu sitio web de producción.

Relacionados

La Coctelera

··567 palabras·3 mins
La Coctelera es un proyecto de código abierto cuyo objetivo es desarrollar una base de datos colaborativa para compartir recetas de cócteles.

Shortbot

··219 palabras·2 mins
Un bot de Telegram que rastrea las posiciones en corto en el IBEX35