Saltar al contenido principal

Configurando CI/CD con Github Actions

Publicado: Noviembre 24, 2025
Actualizado:

Durante varios proyectos, cada despliegue implicaba conectarme al servidor, ejecutar el build, copiar archivos y verificar que todo funcionara correctamente. Repetir estos pasos manualmente en cada actualización aumentaba las posibilidades de olvidar algún paso o introducir inconsistencias entre staging y producción. GitHub Actions apareció como una alternativa para centralizar este proceso en un único workflow automático.

Un workflow automatizado ejecuta siempre la misma secuencia: instala dependencias, construye el proyecto, copia archivos de configuración y despliega al servidor correspondiente. Esto permite que los cambios lleguen al entorno correcto con la misma configuración en cada despliegue.

Creando las llaves SSH para el despliegue

Una forma práctica de permitir que GitHub Actions acceda al servidor es mediante autenticación SSH con pares de llaves. La clave pública se coloca en el servidor, mientras que la privada se guarda como secreto en el repositorio.

Generé el par de llaves desde mi máquina local con el siguiente comando:

ssh-keygen -t rsa -b 4096 -C "breve descripción" -f "C:/Users/santiago/.ssh/id_rsa_github_actions"

Esto generó dos archivos:

  • id_rsa_github_actions (clave privada)
  • id_rsa_github_actions.pub (clave pública)

La clave pública se copia en el archivo authorized_keys del servidor. La clave privada se guarda como secreto en el repositorio de GitHub.

Configuración de secretos en GitHub

La clave privada se carga en el repositorio desde:

Settings → Secrets and variables → Actions → New repository secret

Definí secretos separados para cada entorno:

  • STAGING_HOST, STAGING_USER, STAGING_SSH_KEY
  • PROD_HOST, PROD_USER, PROD_SSH_KEY

Esto permite que el workflow acceda a las credenciales correspondientes según el entorno, sin exponer información sensible en el código.

Captura de pantalla de la sección Secrets and variables/Actions mostrando los repository secrets configurados para el despliegue.

Workflow basado en tags

El workflow unifica staging y producción en un único archivo YAML. La diferencia está en el sufijo del tag que se pushea:

  • *-staging → despliega a staging
  • *-prod → despliega a producción

Cada job evalúa el sufijo del tag con endsWith(github.ref, '-staging') o endsWith(github.ref, '-prod') para determinar qué pasos ejecutar.

El workflow completo:

name: Deploy

on:
  push:
    tags:
      - "*-staging"
      - "*-prod"

jobs:
  deploy-staging:
    if: endsWith(github.ref, '-staging')
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Instalar Node
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Instalando dependencias
        run: npm ci

      - name: Build SvelteKit
        run: npm run build
        env:
          VITE_ENVIRONMENT: staging

      - name: Copiar .htaccess al build
        run: cp .htaccess.staging build/.htaccess

      - name: Copiar robots.txt para staging (bloquear bots)
        run: cp static/robots.staging.txt build/robots.txt

      - name: Deploy via SCP to STAGING
        uses: appleboy/scp-[email protected]
        with:
          host: ${{ secrets.STAGING_HOST }}
          username: ${{ secrets.STAGING_USER }}
          key: ${{ secrets.STAGING_SSH_KEY }}
          source: "build/*,build/.htaccess"
          target: "/home/santiag1/hola.santiagocarranza.net.ar"
          strip_components: 1
          debug: true

  deploy-prod:
    if: endsWith(github.ref, '-prod')
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Instalar Node
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Instalando dependencias
        run: npm ci

      - name: Build SvelteKit
        run: npm run build
        env:
          VITE_ENVIRONMENT: production

      - name: Copiar .htaccess al build
        run: cp .htaccess build/.htaccess

      - name: Copiar robots.txt para producción (permitir bots)
        run: cp static/robots.production.txt build/robots.txt

      - name: Deploy via SCP to PRODUCTION
        uses: appleboy/scp-[email protected]
        with:
          host: ${{ secrets.PRODUCTION_HOST }}
          username: ${{ secrets.PRODUCTION_USER }}
          key: ${{ secrets.PRODUCTION_SSH_KEY }}
          source: "build/*,build/.htaccess"
          target: "/home/santiag1/public_html"
          strip_components: 1
          debug: true

Este enfoque centraliza la configuración de ambos entornos en un único archivo, evitando duplicar lógica y facilitando el mantenimiento del workflow.

Automatizar el despliegue reduce variaciones entre entornos y centraliza la configuración en un único workflow.

Resultado

Automatizar los despliegues eliminó varios pasos que antes hacía manualmente. Ahora subo cambios con git push normalmente, y solo cuando quiero publicar creo un tag. El workflow ejecuta automáticamente el build, copia la configuración correspondiente y despliega al servidor según el entorno.

Captura de pantalla de GitHub en la sección Actions mostrando la ejecución exitosa del workflow de despliegue.

Lo uso en proyectos donde hay múltiples entornos o donde las actualizaciones son frecuentes. No es necesario en todos los casos, pero cuando necesito probar cambios en staging antes de llevarlos a producción, reduce bastante el margen de error.

Top