Files
localesp/docs/07-cicd.md
T
edgar.friendly adb2b4dfe4
deploy-branch / deploy (push) Successful in 2m12s
deploy-branch / teardown (push) Skipped
ci: layout unificado /opt/localesp/<rama>; migrados entornos legacy
2026-07-24 09:56:13 +02:00

4.8 KiB

CI/CD — despliegue por rama

Cada rama se despliega automáticamente en https://<rama>.localesp.es.

Cómo funciona

push a rama X
   │  Gitea Actions  (workflow: .gitea/workflows/deploy.yml)
   ▼
runner self-hosted (host executor, en el propio VPS)
   │  npm ci  →  vite build  →  scripts/deploy.sh <rama>
   ▼
/opt/localesp/<slug>/             código + dist/ + node_modules (prod)
systemd  localesp-<slug>.service node server/index.js  (PORT=80xx)
nginx    <slug>.localesp.es      proxy_pass → localhost:80xx
certbot  *.localesp.es           Let's Encrypt (si el DNS ya apunta)

El slug se deriva del nombre de rama (Feature/Foofeature-foo), válido como hostname DNS. Un entorno = un subdirectorio bajo /opt/localesp/, un servicio, un vhost y un puerto. La base de datos localesp.db de cada entorno se conserva entre despliegues (no se sobreescribe).

Puertos: los históricos son 8080 (prototipo-yb01) y 8081 (master); los nuevos se asignan desde 8082 hacia arriba. Si la rama ya tiene su localesp-<slug>.service, se reutiliza su puerto (adopta el entorno existente).

Precondición manual: el registro DNS

El registro A de <rama>.localesp.es se crea a mano (no está automatizado).

  1. En el proveedor DNS de localesp.es, añade un registro A: <rama>.localesp.es A <IP-pública-del-VPS>
  2. Espera a que propague (dig +short <rama>.localesp.es).
  3. Lanza el workflow (push a la rama, o Actions → Run workflow en Gitea).

Mientras el DNS no apunte al VPS, deploy.sh despliega la app igualmente y la sirve por HTTP; emite el cert Let's Encrypt en cuanto detecta que el DNS ya resuelve. No hay que tocar nada más.

Añadir una rama nueva

git checkout -b mi-feature
# ... cambios ...
git push -u origin mi-feature

El workflow corre solo. Si quieres URL pública: crea el registro A (arriba). Si no, el entorno existe pero no es alcanzable por hostname (útil para tests internos si añades el host a /etc/hosts).

Borrar una rama

Al borrar la rama en Gitea, el job teardown limpia el entorno (unit systemd, vhost, cert y /opt/localesp-<slug>). También manual:

ssh localesp.jumpingcrab.com 'bash /opt/localesp-master/scripts/teardown.sh mi-feature'

Entornos existentes (ya migrados al layout unificado)

Los entornos legacy ya están reubicados bajo /opt/localesp/<rama> con sus systemd units renombradas al esquema localesp-<slug>.service, de modo que el CI los adopta sin cambios (reutiliza puerto y vhost):

Rama Dir Unit Puerto Hosts
master /opt/localesp/master localesp-master.service 8081 localesp.es, master.localesp.es
prototipo-yb01 /opt/localesp/prototipo-yb01 localesp-prototipo-yb01.service 8080 prototipo-yb01.localesp.es

El antiguo localesp.service (sin slug) se retiró; ahora todas las units siguen el patrón localesp-<slug>.service. La db de cada entorno se preservó.

Seguridad

El runner (gitea-runner) se ejecuta como root en el VPS de producción y en modo host (sin contenedor): cualquier workflow que se ejecute corresponde a código del repo corriendo con privilegios de root en la caja. Esto es aceptable mientras el repo sea propio / de baja colaboración. Si entran colaboradores externos, conviene migrar a:

  • runner en contenedor + despliegue por SSH (clave como secret de Gitea), o
  • ephemeral runners (gitea-runner register --ephemeral).

Evolución: estrategia B (wildcard)

Para eliminar la precondición manual del DNS y el cert por rama, más adelante:

  1. Registro wildcard *.localesp.es (DNS).
  2. Wildcard cert *.localesp.es vía challenge DNS-01 (una sola vez).
  3. Un único vhost *.localesp.es que enruta por Host con un map rama→puerto.

deploy.sh apenas cambia: se caen los pasos de creación de vhost y certbot. Nada de lo hecho aquí se pierde.

Infra del runner (referencia)

Instalado en el VPS (localesp.jumpingcrab.com):

  • Binario: /usr/local/bin/gitea-runner (v2.2.0), host executor. Cadena de suministro verificada: el binario coincide (sha256 d6b3f5bb…) con el descomprimido del release oficial gitea-runner-2.2.0-linux-amd64.xz, cuya suma 13357e0d… está publicada en el release. Gitea no publica firma GPG del runner; la suma es la garantía máxima disponible. No hay paquete dnf oficial (solo binario o Docker image).
  • Config: /etc/gitea-runner/config.yaml — etiquetas self-hosted:host, linux:host.
  • Registro: /var/lib/gitea-runner/.runner (instance-level, https://git.localesp.es).
  • Servicio: gitea-runner.service (systemd, User=root, WorkingDirectory=/var/lib/gitea-runner).

Comprobar estado: systemctl status gitea-runner · journalctl -u gitea-runner -f. Ver runners en Gitea: Site administration → Actions → Runners.