@ -8,12 +8,14 @@
# 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.
#
# Lo que se sube :
# Dos decisiones que salen de haberlo hecho una vez a mano, no de suponer :
#
# build/ el servidor ya compilado
# package.json para instalar solo las dependencias de ejecución
# media/audio/ los másteres, que no van en git ni los genera el build
# drizzle/ las migraciones, para poder repasarlas allí
# - **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.
@ -22,12 +24,17 @@ 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
@ -36,38 +43,45 @@ if [[ ! -f build/index.js ]]; then
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"
# `--delete` en build/ para que no se queden restos de versiones anteriores:
# los nombres llevan hash y se acumularían sin fin.
rsync -az --delete build/ " $DESTINO : $RUTA /build/ "
rsync -az package.json package-lock.json drizzle.config.ts " $DESTINO : $RUTA / "
rsync -az --delete drizzle/ " $DESTINO : $RUTA /drizzle/ "
# `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 `--delete`: aquí puede haber material que no esté en esta máquina, y
# borrarlo por descuido sería irreversible.
rsync -az media/audio/ " $DESTINO : $RUTA /media/audio/ "
# Sin borrar lo que hubiera: aquí puede haber material que no esté en esta
# máquina, y perderl o 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 en producción se instala con `--omit=dev`, así que allí no
# existe. Como la base es la misma, da igual desde dónde se lance.
# 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 "==> Instalando dependencias"
ssh " $DESTINO " bash -euo pipefail <<REMOTO
cd " $RUTA "
# Solo lo que hace falta para servir: pg, drizzle-orm y stripe.
npm ci --omit= dev
REMOTO
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 2 && systemctl is-active 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/"
" ${ SSH [@] } " " $DESTINO " "curl -sf -o /dev/null -w 'portada -> %{http_code}\n' http://127.0.0.1:3000/"
echo "Listo."