Logotipo de Bitdoze

Cómo Desplegar Astro en tu VPS con EasyPanel (2026)

Aprende a desplegar un sitio Astro en tu VPS con EasyPanel. Cubre el setup de GitHub, builds zero-config de Railpack, auto-deploy, SSL y dominio propio.

Dragos

20 min de lectura

Cómo Desplegar Astro en tu VPS con EasyPanel (2026)

Astro renderiza páginas a HTML estático por defecto. Tiempos de carga rápidos, ningún runtime que cuidar. Puedes mezclar componentes React, Svelte, Vue o Astro puro en un proyecto. Astro 7 (junio 2026) reescribió el compilador en Rust, y los builds de Astro 7 son entre 15 y 61% más rápidos. El flujo de deploy para sitios estáticos no cambió.

Esta guía recorre el despliegue de un sitio estático Astro en tu propio VPS con EasyPanel. EasyPanel es una PaaS autoalojada sobre Docker con una UI web para apps, bases de datos y SSL. Si aún no está instalado, lee primero la reseña de EasyPanel (2026).

Actualización 2026: Nixpacks está en modo mantenimiento, y EasyPanel ahora recomienda Railpack como el builder automático para apps nuevas. Esta guía está reescrita alrededor de Railpack. Railpack sirve un build estático de Astro con cero config (sin paquete serve, sin script start propio), así que el viejo workaround es ahora una ruta legacy al final del Paso 3.

Artículos relacionados:

Prerequisitos

Antes de empezar:

  • Un VPS con EasyPanel instalado: Ubuntu limpio, 2 GB de RAM mínimo, puertos 80 y 443 libres. La instalación es un comando curl, cubierta en la reseña de EasyPanel.
  • Una cuenta de GitHub.
  • Node.js v22.12.0+ en tu máquina local, requerido por Astro 7. Puedes instalar Node.js 22 con NVM en un par de minutos.
  • Un dominio con un registro A apuntando a la IP de tu VPS. Puedes aplazarlo. EasyPanel da a cada servicio un dominio automático, así que el sitio funciona antes de tocar DNS.

Un VPS de 2 GB corre este setup bien, del orden de 4-6 €/mes, y el plan gratis de EasyPanel cubre hasta 3 proyectos. Esa es toda la factura mensual de un sitio personal.

Si aún no tienes VPS, Hetzner es el default barato y fiable que uso para este tipo de máquina:

Hetzner 20 € de crédito gratis Hostinger VPS

EasyPanel también publica imágenes de marketplace en DigitalOcean y Vultr si quieres el panel preinstalado.

Los precios de VPS saltaron por todos lados en 2026. Si estás replanteando una máquina alquilada, mira qué cambió y cuándo gana un mini PC.

Videoguía

El vídeo muestra la UI antigua de Nixpacks

El flujo del vídeo sigue siendo el mismo: repo, proyecto, build, deploy, dominio. En el paso Build, elige Railpack en vez de Nixpacks. Los pasos de texto de abajo están al día para 2026.

Paso 1: Crea un repositorio en GitHub

Crea un repo nuevo en GitHub. Público o privado valen. Para un repo privado necesitas un token de GitHub en EasyPanel bajo Settings > GitHub. Un personal access token clásico necesita los scopes repo y admin:repo_hook (el segundo solo si quieres auto-deploy; detalles en el Paso 6).

Si necesitas ayuda configurando claves SSH, mira Vincular GitHub con una clave SSH en macOS o Linux.

Clona el repo vacío en local:

bash
git clone git@github.com:yourusername/your-astro-site.git
cd your-astro-site

Paso 2: Inicializa Astro

Corre el asistente de la CLI de Astro dentro del directorio del repo:

bash
npm create astro@latest

Cuando pregunte (la redacción de los prompts varía un poco entre releases menores, pero las preguntas son estables):

  • Project name: usa . para andamiar en el directorio actual
  • Template: elige una plantilla starter, o “Empty” para un proyecto en blanco
  • Install dependencies: yes
  • Initialize git repo: no (ya tienes uno)

Esto crea la estructura estándar de proyecto Astro con src/, public/ y astro.config.mjs. Los scripts de package.json andamiados (dev, build, preview) son todo lo que necesitas para la ruta Railpack. No añades un script start.

Astro sigue usando salida estática por defecto (output: 'static') a menos que actives SSR. Eso es lo que queremos para esta guía; el caso SSR está cubierto en el FAQ.

Paso 3: Configura Astro para hosting estático en EasyPanel

Astro saca HTML estático a dist/. EasyPanel necesita un builder para compilar esa salida y servirla. Tres rutas, dos recomendadas:

  1. Railpack: cero config, la elección por defecto para servicios nuevos.
  2. Dockerfile propio: cuando quieres control total sobre la imagen de runtime.
  3. Nixpacks + serve: legacy, mantenido solo para servicios que ya lo usan.

Opción A: build zero-config con Railpack (recomendado)

Railpack (del equipo de Railway, construido sobre BuildKit) detecta Astro cuando existe astro.config.js y el tipo de salida no es server. Corre tu script build, encuentra el directorio de salida (por defecto dist), y lo sirve con Caddy. Sin paquete serve. Sin script start.

Mantén los scripts andamiados y fija la versión de Node que Astro 7 requiere:

json
{
  "scripts": {
    "dev": "astro dev",
    "build": "astro build",
    "preview": "astro preview"
  },
  "engines": { "node": ">=22.12.0" }
}

Railpack lee engines.node para elegir la versión de Node del build. Alternativas que funcionan igual: un archivo .node-version, un mise.toml, o el campo Mise Packages de EasyPanel (node@22) en los ajustes del servicio. Usa una de estas (no ninguna) o heredas el default que traiga el builder, que es exactamente cómo empieza el “funciona en local, falla en el panel”.

Cero config

Deja los comandos Install, Build y Start vacíos en EasyPanel. La detección de Railpack corre npm install y npm run build, luego sirve dist/ con Caddy. Cualquier cosa que teclees en esos campos pisa la detección, así que hazlo solo cuando la detección esté mal.

Railpack cachea node_modules y .astro entre builds en el mismo servidor, así que los redeploys de un blog pequeño son rápidos una vez construida la primera imagen.

Una nota de ecosistema: Railpack es la misma familia de builder que tienes en Dokploy. Cubro Railpack en Dokploy con un proyecto Python/uv si quieres ver la salida de detección en otro stack.

Opción B: Dockerfile propio para control total

Si prefieres una imagen explícita, deja un Dockerfile en la raíz del proyecto:

dockerfile
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM joseluisq/static-web-server:2-alpine
COPY --from=build /app/dist /public
ENV SERVER_PORT=80

static-web-server va por la v2.44.x al escribir esto; el tag 2-alpine sigue la línea 2.x y sigue al día.

Dos detalles de EasyPanel que vale conocer: los Dockerfiles se buildean con Docker Buildx, y EasyPanel expone GIT_SHA (el commit desplegado) a los builds para deploys de repo. En un Dockerfile, opta por él con ARG GIT_SHA si quieres hornear el commit en la imagen (útil en un footer o un endpoint /healthz).

Cuando existe un Dockerfile, EasyPanel auto-selecciona el builder Dockerfile. También puedes elegirlo explícitamente en la sección Build.

Legacy: la ruta Nixpacks + serve

Nixpacks está en modo mantenimiento

Los docs de Nixpacks llevan un banner diciendo que el proyecto está en modo mantenimiento y recomendando Railpack como reemplazo. Usa esta ruta solo para mantener vivo un servicio Nixpacks existente. Para cualquier cosa nueva, elige Railpack explícitamente. EasyPanel solo recae en Nixpacks cuando no hay Dockerfile y no elegiste otro builder.

Si mantienes un servicio viejo, o quieres el mismo comportamiento que usaba la versión pre-2026 de esta guía:

bash
npm install serve
json
{
  "scripts": {
    "dev": "astro dev",
    "start": "serve dist/",
    "build": "astro build",
    "preview": "astro preview"
  }
}

Nixpacks recoge el script build, luego el script start sirve dist/. serve sigue mantenido (v14.2.x), así que nada se rompe hoy. Solo es una dependencia y un comando start que ya no necesitas en la ruta Railpack.

Paso 4: Verifica el build en local

Pre-vuelo antes de hacer push. Depurar aquí es mucho más fácil que en los logs de deployment.

bash
npm run build
npm run preview

astro preview arranca el propio servidor de preview de Astro en http://localhost:4321. Ábrelo, haz clic por un par de páginas, confirma que el CSS y las imágenes cargan.

Cómo se ve lo roto: npm run build saliendo con código distinto de cero, o el preview sirviendo HTML sin estilos. Arregla ambas cosas aquí. El compilador Rust de Astro 7 es estricto con el markup: tags sin cerrar y atributos sin terminar son errores de build duros ahora, no corregidos en silencio. Si el build falla en markup en local, fallará igual en EasyPanel.

Paso 5: Push a GitHub

bash
git add .
git commit -m "initial astro site"
git push

Una vez encendido el webhook del Paso 6, cada push posterior aquí dispara un deployment nuevo.

Paso 6: Despliega en EasyPanel

Crea un proyecto y un servicio App

  1. En EasyPanel, haz clic en Create Project.
  2. Dentro del proyecto, haz clic en Service y selecciona App.
  3. Conecta tu repositorio de GitHub (flujo de token del Paso 1 si el repo es privado).

Cada servicio App obtiene un dominio automático *.easypanel.host. Eso significa que puedes verificar el deployment de extremo a extremo antes de configurar DNS. Hazlo primero, añade el dominio propio al final.

Configura el build Railpack

Flujo de build de EasyPanel para un sitio Astro estático: repo GitHub, Source con Build Path, build Railpack sirviendo dist/ con Caddy, Save luego Deploy, dominio vivo con SSL

En la sección Source, pon el propietario y nombre del repositorio:

EasyPanel App service Source settings showing GitHub repository owner and name fields

Monorepos: pon Build Path al directorio que contiene package.json y astro.config.mjs. Déjalo vacío para un repo de un solo sitio.

En la sección Build:

  • Elige Railpack del desplegable de builder. Este es el paso importante. El fallback es Nixpacks, y Railpack no se auto-selecciona.
  • Deja Install Command, Build Command y Start Command vacíos. La detección de Railpack corre npm install + npm run build y sirve dist/ con Caddy.
  • Pin de Node opcional: Mise Packages → node@22 (o confía en engines.node de package.json).

Save no es Deploy

Cambiar y guardar el builder no despliega nada. Debes hacer clic en Deploy tras guardar, o el contenedor corriendo se queda en el build viejo.

Haz clic en Save, luego Deploy, y abre el log de acción del deployment. EasyPanel streamea la detección, la instalación de dependencias, la compilación y la salida de creación de imagen. La línea de detección debería decir Astro.

Verifica el deployment

Antes de tocar DNS:

  • La línea de detección de Railpack en el log de build dice Astro, y el build sale limpio.
  • Abre la URL automática *.easypanel.host. El sitio renderiza con estilos e imágenes.
  • curl -I https://tu-dominio-automatico devuelve HTTP/2 200 (también deberías ver un header server de Caddy o Traefik; Traefik frontea el servicio y Caddy sirve los archivos estáticos en la ruta Railpack).
  • Opcional pero útil: haz echo de GIT_SHA (inyectado en los builds para deploys de repo) en algún sitio de la página para saber siempre qué commit está vivo.

Si el dominio automático sirve el sitio, la app está sana. Lo que queda es DNS y certificados.

Activa auto-deploy con un webhook de GitHub

Auto-deploy dispara un build nuevo en cada push al repo. Dos formas de configurarlo:

Botón Auto Deploy

Si conectaste EasyPanel con un token de GitHub, abre el servicio y usa el toggle Enable Auto Deploy (etiquetado “Auto Deploy” en UIs más viejas). Crea el webhook de GitHub por ti. El estado Disable Auto Deploy correspondiente lo quita.

Scopes del personal access token clásico: repo y admin:repo_hook (el segundo es lo que deja a EasyPanel crear el webhook). Los tokens fine-grained también están soportados.

Webhook manual

Copia la URL del webhook desde General en los ajustes de tu proyecto. En tu repo de GitHub ve a Settings > Webhooks, añade la URL, y pon el content type a application/json. GitHub manda un ping de prueba al guardar; la lista de entregas recientes debería mostrar un 200 verde.

Si los pushes no disparan builds, mira Troubleshooting abajo.

Añade tu dominio propio (SSL gratis)

EasyPanel Domains screen with an A record domain and automatic Let's Encrypt SSL
  1. Crea un registro A en tu proveedor de DNS apuntando el dominio (o subdominio) a la IP de tu VPS. La propagación de DNS suele ser de minutos, a veces más. Comprueba con dig +short tudominio.com antes de culpar a EasyPanel.
  2. En EasyPanel, abre Domains del servicio y añade el dominio.
  3. EasyPanel aprovisiona un certificado Let’s Encrypt automáticamente a través de Traefik. Los dominios wildcard también están soportados si los necesitas.

Verifica tras subir el certificado:

bash
curl -I https://yourdomain.com

Espera HTTP/2 200 y una cadena de certificado válida (openssl s_client -connect yourdomain.com:443 -servername yourdomain.com | openssl x509 -noout -dates si quieres ver la expiración).

Consejos de estructura de proyecto

Para un blog o sitio de documentación Astro típico:

text
your-astro-site/
├── src/
│   ├── pages/          # Route-based pages
│   ├── content/        # Markdown/MDX content
│   ├── components/     # Reusable UI components
│   └── layouts/        # Page layouts
├── public/             # Static assets (images, fonts)
├── astro.config.mjs    # Astro configuration
├── package.json
└── tsconfig.json

Para la mayoría de blogs, src/content/ y public/ son los únicos directorios que tocas regularmente. Las integraciones corren en build time, así que añadir una no cambia el flujo de deploy.

bash
npx astro add mdx sitemap

Esto instala y configura las integraciones MDX y sitemap automáticamente.

Extras de Railpack: directorio de salida, modo SPA y un Caddyfile propio

Railpack funciona con cero config para un build Astro estándar, pero hay cuatro mandos que vale conocer:

  • Si tu build no emite a dist, pon la variable de entorno RAILPACK_SPA_OUTPUT_DIR al directorio correcto. La auto-detección cubre dist para Astro.
  • Pon RAILPACK_NO_SPA=1, o da al servicio un comando start propio, cuando quieras que Railpack corra tu servidor Node en vez de servir archivos (el caso SSR, mira el FAQ).
  • Las rutas desconocidas devuelven 404 y sirven 404.html cuando existe. index_fallback por defecto es false. Eso es correcto para un blog Astro multi-página clásico: quieres un 404 real, no la homepage. Solo un build SPA enrutado por cliente quiere index_fallback: true, puesto en un Staticfile en la raíz del proyecto.
  • Deja un Caddyfile en la raíz del proyecto para pisar la plantilla por defecto de Railpack: headers de caché, redirects, headers de seguridad extra.

Los secrets de build-time (un token de CMS privado, por ejemplo) es seguro pasarlos: EasyPanel reenvía las env vars de proyecto y servicio a los builds de Railpack como secrets de BuildKit, así que no acaban en las capas de la imagen.

Lo que EasyPanel te da más allá del build

El build es la mitad de la razón para correr un panel. La otra mitad es todo lo que no tienes que scriptar:

  • HTTPS automático viene de Traefik en 80/443: Let’s Encrypt emite y renueva el certificado por dominio.
  • Un webhook de deploy-trigger dispara un deployment cuando su URL es golpeada. Este es el arreglo limpio para sitios alimentados por CMS. Tu CMS publica, CI golpea el webhook, y listo.
  • HTTP Basic Auth es por servicio y por dominio, desde la pestaña Security. Bien para staging antes de apuntarle un dominio real.
  • Los límites de recursos tapan CPU y memoria por servicio (0 = sin límite). Ponlos en VPS pequeños para que un build tragón de memoria no tumbe la máquina.
  • El modo mantenimiento cambia el tráfico del dominio a una página de mantenimiento mientras arreglas cosas.
  • Las réplicas corren múltiples contenedores de un servicio. Excesivo para un blog, útil cuando una app SSR necesita más de un proceso.
  • El commit desplegado se inyecta en los builds como GIT_SHA.

Undo / rollback: borra el servicio (o el proyecto entero) en EasyPanel y desactiva el webhook de GitHub en el repo. Esas dos acciones revierten completamente un deployment. Para imágenes y volúmenes sobrantes en la máquina, limpia imágenes Docker sin usar y reclama espacio. Para volver a un commit anterior en vez de demoler: git revert o resetea la rama y push, y el webhook rebuildea el estado viejo.

Hardening: una vez el sitio es público, frontearlo con una CDN como Bunny.net CDN mantiene los assets estáticos fuera de tu VPS y esconde la IP de origen. Mantén SSH solo-con-clave, y no expongas puertos del daemon Docker.

Troubleshooting

El build falla en EasyPanel pero funciona en local. Mismatch de versión de Node. Tu portátil corre 22.x, el builder corre algo más viejo. Fíjalo: "engines": { "node": ">=22.12.0" } en package.json, un archivo .node-version, o Mise Packages node@22 en los ajustes del servicio. Si el build es lento en vez de fallar, acelera los builds grandes de Astro.

Nueva clase de fallo con Astro 7

El compilador Rust de Astro 7 trata los tags sin cerrar y los atributos sin terminar como errores de build duros. Si el log apunta a markup que “se ve bien en dev”, corre npm run build en local (falla igual ahí) y arregla el HTML. El modo dev es más indulgente que el compilador de producción.

Página en blanco o 404 en vez del sitio. En la ruta Railpack esto es casi siempre un comando start malo o el directorio de salida equivocado. Limpia el comando Start (el Astro estático no necesita ninguno; Caddy sirve dist/), confirma que dist/ es el directorio de salida del build, y pon RAILPACK_SPA_OUTPUT_DIR si no lo es. Si corres Astro en modo SPA y los deep links dan 404, es el comportamiento de index_fallback descrito arriba.

Los deployments no se disparan en push. Comprueba el webhook primero: repo GitHub → Settings > Webhooks → la URL del payload debe coincidir con la URL del webhook de EasyPanel, content type application/json, y la última entrega debe ser un 200. Confirma también que el toggle Auto Deploy está activado en el servicio.

OOM en el build o el servidor se congela durante el deploy. Un build de Astro puede picar memoria en una máquina de 2 GB, especialmente con procesado de imágenes. Pon un límite de CPU/memoria en el servicio para que el build no pueda matar de hambre al propio Docker, cierra otros servicios mientras despliegas, o añade swap. Si los builds van consistentemente justos de RAM, esa es tu señal para pasar a 4 GB o buildear con más margen.

Imágenes Docker grandes o disco llenándose. Las capas de Nixpacks y BuildKit se acumulan rápido en un disco pequeño. El build multi-stage del Dockerfile de arriba mantiene la imagen de runtime diminuta. Para los restos, limpia imágenes Docker sin usar y reclama espacio con docker system prune y amigos.

Contenido externo no rebuildea. Si el sitio tira de un CMS (Sanity, Contentful y demás), un git push no se dispara cuando solo cambió el CMS. Pulsa Force Rebuild en EasyPanel. Buildea sin la caché de Docker, que es lo que quieres cuando el contenido vive fuera del repo. El arreglo más limpio es el webhook de deploy-trigger de la sección de arriba: el paso de publicación del CMS (o su webhook) llama a la URL y EasyPanel rebuildea. El truco de la env var CACHEBUST ( súbela antes de un rebuild) sigue funcionando en un apuro. Si aún estás eligiendo un headless CMS para Astro, prefiere uno con webhooks de publicación para no pensar en esto nunca más.

FAQ

¿EasyPanel es gratis?

Sí, y el tier gratis es real: hasta 3 proyectos, servicios ilimitados, deployments ilimitados, monitorización básica. Eso cubre la mayoría de sitios personales: un blog, un sitio de docs, una app de staging. Existen tiers de pago para más proyectos y funciones pro: Hobby a 14,9 $/servidor/mes (10,9 $ anual), Growth a 23,9 $ (16,9 $ anual), Business a 37,9 $ (29,9 $ anual), con garantía de reembolso de 30 días. Precios comprobados en octubre de 2026. Re-verifica antes de comprar. El VPS en sí es una factura aparte: más o menos 4-6 €/mes por la máquina de 2 GB que esta guía necesita.

Railpack vs Nixpacks: ¿qué cambió?

Nixpacks está oficialmente en modo mantenimiento; sus docs recomiendan Railpack como reemplazo. EasyPanel ahora lista Railpack como el builder automático preferido para aplicaciones nuevas y posiciona Nixpacks para apps legacy. En la práctica: Railpack es zero-config para Astro estático (corre build, sirve dist/ con Caddy), cachea dependencias entre builds, y está en desarrollo activo. Nixpacks sigue funcionando y sigue necesitando la danza de serve + script start descrita en la sección legacy. Elige Railpack explícitamente en el desplegable Build; EasyPanel recae en Nixpacks si no.

¿Astro 7 cambia el flujo de deploy?

No. La salida estática sigue siendo el default, el directorio dist/ es el mismo, y todo en esta guía funcionaba igual en Astro 5 y 6. Lo que obtienes con Astro 7 es un compilador Rust (builds 15 a 61% más rápidos en sitios grandes), Vite 8, y errores de markup estrictos en build time. El suelo de Node subió: engines.node debe ser >=22.12.0. Astro 6 ya dejó caer Node 18 y 20, así que cualquier cosa corriendo Astro 6 ya está en Node 22. Pon el pin y no notarás diferencia más allá de builds más rápidos.

¿Puedo alojar Astro SSR (salida server) en EasyPanel?

Sí. Selecciona Railpack o un Dockerfile, y no uses el modo de servir static/SPA. Para output: 'server' (o hybrid) Railpack corre el servidor Node en vez de servir archivos. Pon RAILPACK_NO_SPA=1 o da al servicio un comando start explícito (típicamente node dist/server/entry.mjs para un build SSR de Astro), asegúrate de que la app escucha en el puerto que EasyPanel espera, y deja que el proxy maneje TLS. Mismo VPS, mismo panel. La diferencia es que la app mantiene un proceso Node corriendo en vez de Caddy sirviendo archivos estáticos.

Conclusiones

Desplegar Astro en EasyPanel en 2026 es un trabajo corto: repo GitHub, npm create astro@latest, push, build Railpack, botón Deploy, dominio. Railpack quitó la parte quisquillosa (sin paquete serve, sin script start), y EasyPanel te da SSL automático, un webhook de deploy y límites de recursos sin tooling extra.

El plan gratis soporta hasta 3 proyectos (los tiers de pago empiezan en 10,9 $/servidor/mes anual), y sigues pagando solo el VPS. Un panel de 0 $ más un VPS de ~5 € es toda la factura mensual de un sitio personal, más barato que plataformas gestionadas como Netlify o Vercel, con control total sobre la máquina.

Si estás eligiendo panel en vez de solo seguir esta guía, compara cómo se mide EasyPanel contra Coolify, Dokploy y Kamal, o recorre los mejores paneles de servidor autoalojados. Y si quieres la ruta de coste cero sin servidor en absoluto, puedes crear un blog Astro gratis con Cloudflare.

Hetzner 20 € de crédito gratis Hostinger VPS