Objetivo: Eliminar el proceso manual de compilar y copiar la carpeta public/ al servidor. Implementaremos un pipeline que, al detectar un git push en la rama principal, compile el sitio y lo transfiera vía SFTP de forma segura utilizando llaves SSH.
Seguridad: Implementación del menor privilegio
En entornos de producción reales, no usamos root. El despliegue se realiza con un usuario restringido que solo tiene acceso a su propio directorio personal. Esto añade una capa de seguridad vital: si el proceso de CI/CD se ve comprometido, el atacante queda atrapado en una “jaula” dentro del $HOME del usuario.
Fase 1: Preparación del Servidor (VPS)
Para que GitHub Actions pueda acceder al VPS sin interacción humana, necesitamos autenticación basada en llaves SSH (sin contraseña).
Abre la terminal y conéctate a tu VPS.
Genera un nuevo par de llaves criptográficas (cuando pida passphrase, presiona Enter para dejarlo en blanco):
ssh-keygen -m PEM -t rsa -b 4096 -f ~/.ssh/github_actions -C "github-cicd"

- Autoriza la llave pública en el servidor:
# Append the new public key to authorized_keys
cat ~/.ssh/github_actions.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

- Imprime la llave privada en pantalla y cópiala completa (desde
-----BEGINhastaEND-----):
# Read private key to copy to GitHub Secrets
cat ~/.ssh/github_actions

Fase 2: Configuración de GitHub Secrets
Por seguridad, las credenciales del servidor jamás deben ir en el código.
- Ve a tu repositorio en GitHub > Settings > Secrets and variables > Actions.

- Crea los siguientes Repository secrets:

Repite el proceso para cada “variable”.
FTP_SERVER: La IP pública o dominio de tu VPS (ej.198.51.100.1).FTP_USERNAME: Tu usuario SSH (ej.rootoadmin).FTP_PORT:22(o el puerto SSH personalizado que uses).FTP_SSH_KEY: Pega aquí el contenido exacto de la llave privada que copiaste en la Fase 1.
Fase 3: Creación del Pipeline (YAML)
Dado que tenemos una estructura tipo Monorepo (donde el blog vive dentro de la subcarpeta mxlit-blog/), configuraremos el workflow para que solo compile y despliegue cuando haya cambios específicos en ese directorio.
- En la raíz de tu repositorio local (al nivel de la carpeta
mxlit-site), crea la ruta:.github/workflows/.

- Dentro, crea un archivo llamado
deploy-mxlit.ymly pega este código:
name: Deploy MXLIT to VPS via SFTP
on:
push:
branches:
- main
paths:
- 'mxlit-site/mxlit-blog/**'
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
- name: Setup Hugo
uses: peaceiris/actions-hugo@v3
with:
hugo-version: 'latest'
extended: true
- name: Build Hugo site
run: hugo --source mxlit-site/mxlit-blog --minify
- name: SFTP Deploy
uses: wlixcc/[email protected]
with:
username: ${{ secrets.FTP_USERNAME }}
server: ${{ secrets.FTP_SERVER }}
port: ${{ secrets.FTP_PORT }}
ssh_private_key: ${{ secrets.FTP_SSH_KEY }}
local_path: './mxlit-site/mxlit-blog/public/*'
remote_path: '/YourPathHere' #<----------- Add your path here!
# Ensure old files are removed from the destination to keep it clean
delete_remote_files: true
args: '-o ConnectTimeout=5'

Fase 4: Despliegue a Producción
El pipeline ya está configurado. El flujo de trabajo diario ahora es simplemente:
Escribir o modificar contenido en Obsidian.
Abrir la terminal y ejecutar:
# Add changes, commit, and push to trigger the pipeline
git add .
git commit -m "docs: add cicd pipeline documentation"
git push origin main
- Ir a la pestaña Actions en GitHub para ver la compilación en tiempo real (toma menos de 30 segundos).

Conclusión
Implementar un flujo de CI/CD para un sitio estático no es solo una cuestión de comodidad; es una estrategia para garantizar que el despliegue sea predecible, seguro y libre de errores humanos. Al pasar de un proceso manual de copia por SFTP a una automatización basada en eventos con GitHub Actions, transformamos nuestro repositorio en la única “fuente de verdad” (Single Source of Truth).
Esta arquitectura monorepo nos permite escalar otros proyectos bajo el mismo paraguas de Git, manteniendo una separación clara de responsabilidades y un historial de cambios auditable. Ahora, el enfoque vuelve a ser lo más importante: crear contenido de valor, sabiendo que la infraestructura se encarga del resto en cuestión de segundos.