#!/usr/bin/env bash # # Despliegue por SSH, sin repositorio remoto. # # ./despliegue/desplegar.sh senzapaura@192.168.18.171 # # Construye aquí y sube el resultado. Se hace así y no compilando en el servidor # porque el servidor no necesita las herramientas de desarrollo —ni Vite, ni # Playwright, ni el compilador— para servir la web: solo Node y tres paquetes. # # Dos decisiones que salen de haberlo hecho una vez a mano, no de suponer: # # - **Se sube con `tar` por SSH, no con `rsync`.** La máquina de desarrollo es # Windows y Git Bash no trae rsync. Tar sí, y está en los dos lados. # - **Las dependencias se resuelven aquí y se suben ya instaladas.** El servidor # tiene salida a internet pero su DNS no resuelve `registry.npmjs.org`, así # que `npm ci` allí falla. Da igual: los tres paquetes de producción son # JavaScript puro, sin binarios de plataforma, y viajan tal cual. # # Lo que NO se sube: `.env`. Las claves se ponen a mano en el servidor una vez # y se quedan ahí. Subirlas en cada despliegue es cómo acaban en un historial. set -euo pipefail DESTINO="${1:-}" RUTA="${2:-/var/www/senzapaura}" CLAVE="${SSH_CLAVE:-$HOME/.ssh/senzapaura_deploy}" if [[ -z "$DESTINO" ]]; then echo "uso: $0 usuario@servidor [ruta]" >&2 exit 1 fi SSH=(ssh -i "$CLAVE" -o BatchMode=yes) TEMPORAL="$(mktemp -d)" trap 'rm -rf "$TEMPORAL"' EXIT echo "==> Construyendo" node scripts/construir.mjs if [[ ! -f build/index.js ]]; then echo "el build no ha dejado build/index.js; se aborta" >&2 exit 1 fi echo "==> Resolviendo dependencias de producción" cp package.json package-lock.json "$TEMPORAL/" (cd "$TEMPORAL" && npm ci --omit=dev --silent) # Un binario compilado para Windows no arrancaría en el servidor. Hoy no hay # ninguno, pero si algún día se añade una dependencia que lo traiga, es mejor # enterarse aquí que con el servicio caído. if find "$TEMPORAL/node_modules" -name '*.node' | grep -q .; then echo "hay binarios de plataforma en node_modules: instálalos en el servidor" >&2 find "$TEMPORAL/node_modules" -name '*.node' | head -5 >&2 exit 1 fi echo "==> Subiendo la aplicación" # `build` se borra antes: los nombres llevan hash y si no se acumularían sin fin. tar -czf - build package.json package-lock.json drizzle.config.ts drizzle | "${SSH[@]}" "$DESTINO" "rm -rf '$RUTA/build' '$RUTA/drizzle' && tar -xzf - -C '$RUTA'" echo "==> Subiendo dependencias" tar -czf - -C "$TEMPORAL" node_modules | "${SSH[@]}" "$DESTINO" "rm -rf '$RUTA/node_modules' && tar -xzf - -C '$RUTA'" echo "==> Subiendo el audio privado" # Sin borrar lo que hubiera: aquí puede haber material que no esté en esta # máquina, y perderlo sería irreversible. tar -czf - media/audio | "${SSH[@]}" "$DESTINO" "tar -xzf - -C '$RUTA'" echo "==> Migrando la base de datos" # Desde aquí y no en el servidor: `drizzle-kit` es una herramienta de desarrollo # y allí no se instala. Como la base es la misma, da igual desde dónde se lance. npm run db:migrate echo "==> Reiniciando" # Requiere que el usuario pueda reiniciar este servicio sin contraseña. En # /etc/sudoers.d/senzapaura: # senzapaura ALL=(root) NOPASSWD: /bin/systemctl restart senzapaura "${SSH[@]}" "$DESTINO" "sudo systemctl restart senzapaura && sleep 3 && systemctl is-active senzapaura" echo "==> Comprobando que responde" "${SSH[@]}" "$DESTINO" "curl -sf -o /dev/null -w 'portada -> %{http_code}\n' http://127.0.0.1:3000/" echo "Listo."