Logotipo de Bitdoze

Cómo Desplegar Astro en un VPS con CloudPanel (Guía 2026)

Aprende a desplegar Astro en un VPS con CloudPanel: compila un sitio estático, añade SSL y el CDN de Cloudflare, automatiza los rebuilds y revierte despliegues con seguridad en tu servidor.

Dragos

21 min de lectura

Cómo Desplegar Astro en un VPS con CloudPanel (Guía 2026)

Desplegar Astro en un VPS con CloudPanel te da lo único que las plataformas gratuitas nunca ofrecen: control total. Tu build, tus cabeceras de caché, tu ruta de rollback y sin límites de minutos de build esperando para sorprenderte a final de mes. El hosting gratuito como Cloudflare Pages, Vercel y Netlify funciona bien hasta que deja de hacerlo: límites de ancho de banda, límites de build o lock-in de plataforma.

CloudPanel es un panel de hosting gratuito que corre sobre Nginx. Gestiona la administración de sitios, el SSL y el aislamiento de usuarios a través de una interfaz web. Despliegas Astro como un Static HTML site y dejas que CloudPanel sirva los archivos compilados directamente desde Nginx. Ningún proceso de Node.js corre en runtime, lo que significa que un VPS pequeño y barato es suficiente. Y desde que Astro 7 salió en junio de 2026 con builds entre un 15 y un 61 % más rápidos (nuestro benchmark de builds de Astro 7), los rebuilds en esa máquina pequeña son más rápidos que antes.

DigitalOcean 100 $ gratis Vultr 100 $ gratis Hetzner 20 € gratis Hostinger VPS

Los precios de los VPS subieron en todos los proveedores en 2026. Si estás replanteándote una máquina alquilada, mira qué cambió y cuándo gana un mini PC.

Prerequisitos

Antes de empezar, esto es lo que ya tiene que existir:

El stack que monta esta guía: VPS Linux + CloudPanel (Nginx) + NVM + Node 24 + Cloudflare delante. Todo lo demás es opcional.

Mantén CloudPanel actualizado

El changelog de CloudPanel muestra un historial real de CVEs, incluidos fixes de escalada de privilegios entre 2022 y 2024. La versión actual es v2.5.4 (2026-07-01). Ejecuta la rutina de actualización del panel tras instalarlo y no lo dejes obsoleto. Estás exponiendo una UI de administración en una IP pública.

También puedes desplegar Astro en un VPS con Coolify o EasyPanel si prefieres otro panel. Para stacks pesados en Docker son buenas opciones. Para un sitio Astro puramente estático, CloudPanel es el camino más simple.

Si quieres monitorizar CPU, memoria y espacio en disco de tu servidor, mira: Cómo monitorizar recursos de servidor y Docker

Videoguía

El vídeo muestra una UI anterior de CloudPanel

La videoguía se grabó en 2023. El flujo es el mismo, pero la UI de CloudPanel v2.5.x difiere en algunos puntos. Los pasos escritos de abajo están al día para CloudPanel v2.5.4 (2026-07-01). Fíate de ellos si las capturas no coinciden con lo que ves.

Desplegar Astro.js en un VPS con CloudPanel

Hay dos enfoques en CloudPanel: un Static HTML site (recomendado para salida puramente estática) o un Node.js site. El enfoque Static HTML es más simple y barato de correr: CloudPanel sirve los archivos compilados directamente desde Nginx sin ningún proceso Node.js en runtime. Esta es la secuencia completa: sitio, DNS, SSL, Node para compilar, proyecto, build y automatización.

Paso 1: Añade un sitio Static HTML en CloudPanel

  1. Inicia sesión en tu panel de administración de CloudPanel.
  2. Ve a Sites > Add Site > Create a Static HTML Site. (La documentación actual de CloudPanel para todos los tipos de sitio está en cloudpanel.io/docs/v2/frontend-area/add-site/.)
  3. Introduce tu nombre de dominio y crea las credenciales del usuario del sitio.
  4. Cuando el sitio esté creado, edítalo y cambia el Root Directory para que apunte al directorio dist:
text
htdocs/www.yourdomain.com/dist

Astro genera su build de producción en dist/ por defecto (outDir: './dist'). CloudPanel tiene que servir desde ese directorio, no desde la raíz del proyecto.

Sirve siempre desde dist/, nunca desde la raíz del proyecto

Servir la raíz del proyecto expondría tu directorio .git/, node_modules/, los archivos fuente y el .env a través de Nginx. Apunta el root directory a dist/ y nada más será accesible. Si obtienes un 403 o un 404 tras un build “correcto”, este ajuste es lo primero que debes revisar.

Ajustes del sitio en CloudPanel con el Root Directory configurado a htdocs/www.yourdomain.com/dist para un build de Astro

CloudPanel también crea la redirección www↔non-www y fuerza HTTP→HTTPS por ti. No necesitas escribir esas reglas a mano.

Paso 2: Apunta el DNS a tu VPS

Añade un registro A en tu proveedor de DNS apuntando tu dominio a la dirección IP del VPS. Si usas Cloudflare, añade el registro A allí y activa el proxy para las ventajas del CDN y la protección DDoS.

bash
dig +short www.yourdomain.com
# With Cloudflare proxy on, you'll see Cloudflare IPs (that's expected)
# With proxy off (DNS only), you should see your VPS IP
Registro A de DNS en Cloudflare apuntando el dominio a la IP del VPS con el proxy de Cloudflare activado

Configura el SSL/TLS de Cloudflare en Full (strict)

Con un certificado Let’s Encrypt en el origen (siguiente paso) y Cloudflare delante, pon el modo SSL/TLS en Full (strict) en el dashboard de Cloudflare. El modo Flexible por defecto hace que Cloudflare hable HTTP con tu origen mientras sirve HTTPS a los visitantes. Eso provoca bucles de redirección con las reglas de HTTPS forzado de Nginx, o errores 522/525. Full (strict) verifica el certificado del origen y el bucle desaparece.

Paso 3: Genera un certificado SSL de Let’s Encrypt

En CloudPanel, ve a la sección SSL/TLS de tu sitio y haz clic en New Let’s Encrypt Certificate. CloudPanel gestiona la generación del certificado y la configuración de Nginx automáticamente.

Verifícalo antes de seguir:

bash
curl -I https://www.yourdomain.com
# Expect: HTTP/2 200 (the CloudPanel placeholder page is fine at this stage)

curl -I http://www.yourdomain.com
# Expect: 301 redirect to https://www.yourdomain.com

Si curl te da un aviso de certificado, el certificado no se emitió. Comprueba que el registro DNS del Paso 2 ya resuelve antes de reintentar.

Paso 4: Instala Node.js 24 LTS con NVM

Astro necesita Node.js para compilar el sitio. CloudPanel crea usuarios de Linux aislados por sitio, así que instala Node.js bajo el usuario del sitio, no como root. Entra por SSH a tu VPS y cambia al usuario del sitio:

bash
ssh root@your-server-ip
sudo su - www.yourdomain.com

Instala NVM (Node Version Manager). La v0.40.8 es la versión actual a septiembre de 2026:

bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.8/install.sh | bash
source ~/.bashrc

Instala Node.js 24, la línea LTS activa:

bash
nvm install 24
nvm alias default 24

Verifica la instalación:

bash
node -v
# Should output v24.x.x

nvm ls
# Should show v24.x.x as default

Astro 7 necesita Node >= 22.12.0

La línea de versiones actual de Astro (7.x, 7.3.5 en npm a octubre de 2026) requiere node >=22.12.0. Node 24 lo cumple y tiene soporte hasta 2028-04-30. Node 22 aún funciona (LTS de mantenimiento hasta 2027-04-30). nvm install 22 instala el 22.x más reciente, que supera el mínimo de 22.12.0, pero 24 te da un año extra de soporte. Instala 24 salvo que tengas una razón para no hacerlo.

Paso 5: Clona y configura tu proyecto Astro

Elimina los archivos de ejemplo que CloudPanel crea por defecto y coloca tu proyecto. El nombre del directorio debe coincidir con lo que CloudPanel espera (www.yourdomain.com).

Clonar un repo existente

bash
cd htdocs
rm -rf www.yourdomain.com
git clone [email protected]:your-username/your-astro-repo.git www.yourdomain.com
cd www.yourdomain.com
npm install

Para un repo privado, [email protected]:... necesita una clave SSH para el usuario del sitio. Crea una y añádela al repo como deploy key de solo lectura:

bash
ssh-keygen -t ed25519 -C "deploy-www.yourdomain.com"
cat ~/.ssh/id_ed25519.pub
# Copy the output, then in GitHub: repo Settings > Deploy keys > Add deploy key
# Paste it and leave "Allow write access" unchecked

Si necesitas una guía más detallada de claves SSH con GitHub, mira cómo vincular GitHub con una clave SSH.

Crear un proyecto nuevo

bash
cd htdocs
rm -rf www.yourdomain.com
npm create astro@latest www.yourdomain.com
cd www.yourdomain.com
npm install

Esto sigue generando proyectos Astro 7 correctamente. Para un tema de blog ya hecho, mira Bitdoze Astro Theme o AstroWind.

¿Permission denied (publickey)?

Ese error en git clone o git pull significa que el usuario del sitio no tiene ninguna clave SSH registrada en GitHub. Los pasos de la deploy key de arriba son la solución. Prueba con ssh -T [email protected] como usuario del sitio. Deberías ver “Hi username/repo! You’ve successfully authenticated”.

Paso 6: Compila el sitio estático de Astro

Cuando tu sitio esté configurado y el contenido en su lugar, compila la versión de producción:

bash
npm run build

Esto genera los archivos estáticos en dist/. Como el root directory de CloudPanel ya apunta a dist/, el sitio entra en producción en el momento en que termina el build.

Verifica:

bash
curl -I https://www.yourdomain.com
# Expect: HTTP/2 200 and content-type: text/html

curl -I https://www.yourdomain.com/_astro/*.css
# Expect: 200. Astro emits hashed assets under /_astro/

¿OOM-killed en un VPS de 1 GB?

npm install y los builds de Astro pueden consumir más de 1 GB de RAM, y el OOM killer del kernel abortará el build encantado. Redimensiona a 2 GB o añade de 1 a 2 GB de swap primero:

bash
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Los builds más rápidos de Astro 7 (de un 15 a un 61 %, nuestro benchmark de builds de Astro 7) acortan la ventana pero no eliminan el mínimo de memoria. Para sitios pesados, mira optimización de la velocidad de build de Astro.

¿Recompilando un sitio viejo de Astro 4/5/6 en Astro 7?

El nuevo compilador Rust de Astro 7 ya no corrige el markup silenciosamente. Las etiquetas sin cerrar y los atributos sin terminar ahora son errores de build duros, y los espacios en blanco entre elementos inline se colapsan al estilo JSX (los saltos de línea ya no se renderizan como un espacio; usa { ' ' } donde necesites uno). Si te encuentras un muro de errores de markup después de que npm install trajera Astro 7, ese es el motivo. Ruta de actualización: npx @astrojs/upgrade, y luego corrige las líneas reportadas.

Paso 7: Automatiza rebuilds y despliegues

Hacer pull y build a mano cansa al tercer push de contenido. Todo el pipeline es pequeño:

Pipeline de despliegue de Astro: un git push dispara un script de deploy que ejecuta git pull, npm ci y npm run build en dist, que el Nginx de CloudPanel sirve por HTTPS a través de Cloudflare al visitante

Escribe un script de deploy mínimo como usuario del sitio, en ~/deploy.sh:

bash
#!/usr/bin/env bash
set -euo pipefail

cd ~/htdocs/www.yourdomain.com
git pull
npm ci
npm run build
bash
chmod +x ~/deploy.sh

Usa npm ci en lugar de npm install. Instala exactamente lo que hay en package-lock.json, así que un rebuild mañana se comporta como el rebuild de hoy. Ahora elige un disparador:

Cron de CloudPanel

En CloudPanel, ve a Cron Jobs del usuario del sitio y ejecuta el script en un horario, por ejemplo cada 5 minutos:

bash
*/5 * * * * /home/www.yourdomain.com/deploy.sh >> /home/www.yourdomain.com/deploy.log 2>&1

Para evitar rebuilds innecesarios, añade un check de fetch al principio del script:

bash
cd ~/htdocs/www.yourdomain.com
git fetch -q
[ "$(git rev-parse HEAD)" = "$(git rev-parse @{u})" ] && exit 0

El build solo corre cuando el remoto tiene commits nuevos. Tosco, fiable, sin puertos de entrada.

Webhook de GitHub

Añade un webhook en GitHub (Settings > Webhooks del repo): URL de payload apuntando a un listener mínimo en el VPS que ejecuta deploy.sh, content type application/json, evento “Just the push event”.

El listener puede ser un servicio Python de 20 líneas o un script de shell tras un endpoint desechable. Apúntalo a una ruta que no sea el vhost de tu sitio web y ponle un secreto compartido. Si no, cualquiera que encuentre la URL puede disparar builds en tu servidor. Las deploy keys son de solo lectura; el listener del webhook es la única superficie de entrada que añades.

DPLOY

CloudPanel incluye una herramienta de despliegue nativa de Git, DPLOY. Haces push a una rama, DPLOY hace pull y ejecuta tu comando de build. Es la opción “nativa” si quieres que el panel sea dueño del flujo de deploy en lugar de cron más un script de shell.

Revisa la página de docs para los pasos de instalación actuales. La documentación sigue activa y corresponde a la v2.

Uses el disparador que uses: la salida del build acaba en los logs de cron o en el journal del webhook. Cuando un deploy “silenciosamente” no ocurre, ese log es el primer sitio donde mirar. El script es también donde se engancha la salvaguarda de rollback (lo vemos a continuación).

DigitalOcean 100 $ gratis Vultr 100 $ gratis Hetzner 20 € gratis Hostinger VPS

Revertir un deploy fallido

npm run build vacía dist/ antes de escribir la salida nueva. Si el build falla a medias (error de markup, OOM kill, dependencia rota), puedes quedarte sirviendo nada. La solución es aburrida: guarda el build bueno anterior hasta que el nuevo esté probado.

Diagrama de intercambio para rollback: antes de un rebuild mueve dist a dist.last-known-good, ejecuta el build que vacía dist primero y puede fallar, y luego en caso de éxito elimina el backup o en caso de fallo devuelve el backup para que el sitio siga sirviendo

Extiende el script de deploy con el intercambio:

bash
#!/usr/bin/env bash
set -euo pipefail

cd ~/htdocs/www.yourdomain.com
git pull
npm ci

# Keep the previous build until the new one is proven
if [ -d dist ]; then
  rm -rf dist.last-known-good
  mv dist dist.last-known-good
fi

if npm run build && [ -f dist/index.html ]; then
  rm -rf dist.last-known-good
else
  echo "Build failed or produced no index.html, restoring previous dist" >&2
  if [ -d dist.last-known-good ]; then
    rm -rf dist
    mv dist.last-known-good dist
  fi
  exit 1
fi

La comprobación [ -f dist/index.html ] atrapa el peor caso: un build que sale con código 0 pero emite un árbol de salida vacío o incorrecto. Si falla, el backup vuelve a su sitio y Nginx sigue sirviendo la versión anterior.

Esto es una estrategia de “última salida estática buena conocida”, no despliegues versionados. Para un sitio estático en solitario es suficiente: el tiempo de restauración es un mv, y el único estado que importa (el repo git) está en otra parte.

Verifica el despliegue y configura las cabeceras de caché

Ejecuta este checklist tras el primer deploy y tras cada rebuild. Lleva 30 segundos y atrapa la mayoría de lo que se rompe:

Luego el caché. Astro emite archivos hasheados bajo /_astro/, así que esos se pueden cachear fuerte: Cache-Control: public, max-age=31536000, immutable. El HTML debe tener una vida corta; si no, los visitantes siguen viendo el deploy anterior tras un rebuild.

La plantilla de vhost estático de CloudPanel gestiona el serving básico, pero si quieres cabeceras explícitas y predecibles, añádelas en el editor Vhost del sitio (docs de vhost de CloudPanel):

nginx
location /_astro/ {
  add_header Cache-Control "public, max-age=31536000, immutable";
}

Deja el HTML con el manejo por defecto, o pon un Cache-Control corto (60 segundos es de sobra). En el lado de Cloudflare, pon Browser Cache TTL en “Respect Existing Headers” para que gane el origen. Así un rebuild se ve sin necesidad de purgar.

¿Los deploys no aparecen?

Dos sospechosos habituales: un TTL de caché de HTML largo (solución arriba), o el edge de Cloudflare aún guardando la página vieja. Purga la caché de Cloudflare para las páginas HTML tras un deploy si lo necesitas en vivo inmediatamente. Los assets de /_astro/ no necesitan purga. Sus nombres de archivo cambian cuando cambia su contenido.

Cuando el sitio esté en vivo, vigílalo: monitoriza el uptime con Beszel y Uptime Kuma y sigue los recursos del servidor. Un sitio estático también puede caerse: expiración del certificado, disco lleno, mala configuración de Nginx en la próxima edición.

Si prefieres no poner Cloudflare delante, Bunny.net funciona como CDN edge drop-in sobre el mismo origen. Pull zone apuntando a tu VPS, la misma historia de caché inmutable de /_astro/.

Solución de fallos comunes

La mayoría se arreglan en 2 minutos

Cada entrada de abajo es error → causa → solución. El recorrido completo de cada una está en el paso enlazado dentro.

git clone o git pull falla con Permission denied (publickey)

El usuario del sitio no tiene ninguna clave SSH que GitHub conozca. Genera una (ssh-keygen -t ed25519 como usuario del sitio), añade la clave pública al repo como deploy key de solo lectura y prueba con ssh -T [email protected]. Pasos completos en el Paso 5. Variante común: añadiste la clave a tu cuenta personal de GitHub pero el repo está en una organización que restringe las deploy keys. Usa una deploy key del repo en su lugar.

El build muere en un VPS pequeño (npm install o astro build)

Falta de memoria. En máquinas de 1 GB el OOM killer del kernel aborta el build sin ningún error útil de Astro. Solución: añade de 1 a 2 GB de swap (comandos en el Paso 6) o redimensiona el VPS a 2 GB. Comprueba dmesg -T | grep -i oom para confirmar que es OOM y no otra cosa. Los builds más rápidos de Astro 7 acortan la ventana pero no bajan el mínimo de memoria.

Bucle de redirección o errores 522/525 tras Cloudflare

El modo SSL/TLS de Cloudflare probablemente está en Flexible, así que Cloudflare habla HTTP con tu origen mientras Nginx fuerza HTTPS. Eso es una redirección infinita. Pon SSL/TLS en Full (strict) con el certificado Let’s Encrypt en el origen. Detalles en el Paso 2.

Errores de build duros tras actualizar a Astro 7

El nuevo compilador Rust ya no corrige el markup silenciosamente: etiquetas sin cerrar y atributos sin terminar son errores de build, y los espacios en blanco inline se comportan al estilo JSX. Corrige las líneas reportadas, o ejecuta npx @astrojs/upgrade y trabaja la lista. Detalles en el Paso 6.

El sitio muestra 404 o 403 tras un build correcto

El root directory no está apuntando a dist/. En CloudPanel, edita el sitio y pon el Root Directory en htdocs/www.yourdomain.com/dist. Si el directorio es correcto y dist/index.html no existe, la salida del build fue a otra parte: revisa outDir en astro.config.mjs. Servir la raíz del proyecto en lugar de dist/ “arregla” el 404 y expone .git/. No lo hagas.

El deploy corrió pero los visitantes siguen viendo el sitio viejo

Caché. O el navegador retiene un TTL de HTML largo, o el edge de Cloudflare aún no lo ha expirado. Acorta la caché de HTML (ver la sección de verificación), purga Cloudflare tras el deploy si debe ser instantáneo, y confirma con curl -s https://www.yourdomain.com | grep -o '_astro/[^\"]*\.css' que se están sirviendo nombres de assets hasheados nuevos.

Alternativa: usa el tipo de sitio Node.js de CloudPanel

Static HTML site (recomendado)

Sirve dist/ directamente desde Nginx. Ningún proceso Node.js en runtime.

  • Menor huella de memoria. Un VPS de 1 a 2 GB es de sobra
  • Nada que mantener vivo (sin PM2, sin gestor de procesos)
  • Rebuild con Node, serving con Nginx

El default correcto para cualquier sitio Astro puramente estático.

Node.js site

CloudPanel gestiona la versión de Node.js vía NVM y hace proxy a un puerto de la app.

  • Elige Node.js version 24 LTS (soportado desde CloudPanel v2.5.4, 2026-07-01; 22 sigue seleccionable)
  • Configura un puerto de app (p. ej. 3000) y corre la app con un gestor de procesos
  • Necesario solo si más adelante cambias a SSR con un adapter

La misma versión de Node que instalarías a mano en el flujo estático, solo que gestionada por el panel. El coste es un proceso Node permanente consumiendo RAM 24/7.

Para un sitio puramente estático, usa el tipo Static HTML site. Siempre puedes recrear el sitio como Node.js más adelante si pasas a SSR. Es un cambio de 10 minutos. Si aún estás decidiendo el panel en general, la comparativa de mejores paneles de servidor self-hosted cubre los trade-offs.

Conclusión

Desplegar Astro en un VPS con CloudPanel es el movimiento correcto cuando te quedas corto con los límites del hosting gratuito o quieres control sobre la máquina. El tipo de sitio Static HTML es su versión más simple: Nginx sirve dist/, ningún proceso Node corre en runtime, un VPS de 5 a 10 $/mes es suficiente, y los builds más rápidos de Astro 7 hacen que los rebuilds en esa máquina pequeña duelan menos. Añade el script de deploy, el intercambio de dist.last-known-good y el checklist de verificación, y tendrás una ruta de deploy en la que puedes confiar a la 1 de la madrugada.

Un repaso de seguridad: mantén CloudPanel actualizado. El panel corre con privilegios reales en tu servidor y el changelog muestra el historial de CVEs que demuestra que importa.

DigitalOcean 100 $ gratis Vultr 100 $ gratis Hetzner 20 € gratis Hostinger VPS

Si quieres un panel web que también funcione como reverse proxy para contenedores Docker, mira este curso:

Curso de configuración de CloudPanel

Adónde ir después: