---
title: "Cómo Crear un Blog Astro Gratis con Cloudflare en 30 Minutos"
description: "Aprende a crear un blog Astro gratis y desplegarlo en Cloudflare Pages en 30 minutos: sin tarjeta, sin costes de hosting, paso a paso para principiantes totales."
date: 2026-10-15
categories: ["web-development"]
tags: ["astro","cloudflare","static-site"]
---

import Button from "@components/widgets/Button.astro";
import Notice from "@components/widgets/Notice.astro";
import ListCheck from "@components/widgets/ListCheck.astro";
import Accordion from "@components/widgets/Accordion.astro";
import Tabs from "@components/widgets/Tabs.astro";
import Tab from "@components/widgets/Tab.astro";
import YouTubeEmbed from "@components/widgets/YouTubeEmbed.astro";

¿Quieres un blog que no cueste nada alojar? Esta guía construye un blog Astro gratis y lo despliega en Cloudflare Pages en unos 30 minutos. Sin tarjeta y sin facturas de hosting.

No necesitas saber JavaScript ni ningún framework. Si puedes pegar comandos en una terminal, puedes seguir la guía.

<Notice type="success" title="Actualización: el tema acaba de recibir un boost de velocidad">
El [Bitdoze Astro Theme](https://github.com/bitdoze/bitdoze-astro-theme) que harás fork en el Nivel 4 ahora corre sobre **Astro 7**. El nuevo compilador Rust de Astro redujo los tiempos de build aproximadamente a la mitad en este mismo blog (743 páginas, de 103s a 47s), y aproveché la actualización para añadir una suite de tests real con Vitest, un esquema de contenido más estricto y un arreglo de sitemap al tema. Nada de lo de abajo cambia para ti: `npm install` simplemente trae la versión más rápida. Cifras completas aquí: [Astro 7 Benchmark: Tiempos de Build Reducidos a la Mitad](/astro-7-faster-builds/).

Una nota de honestidad: el vídeo y las capturas de esta guía se grabaron antes de que aterrizara Astro 7 y antes de que Cloudflare renombrara el nav del dashboard a **Workers & Pages**. Los pasos escritos de abajo son la fuente de verdad para los archivos de config y el flujo de despliegue.
</Notice>

## ¿Qué demonios es Astro?

[Astro](https://astro.build/) es un generador moderno de sitios estáticos. Construyes páginas con tu framework de UI favorito (React, Vue, Svelte) o con Markdown a pelo, y Astro envía cero JavaScript por defecto.

Mientras otros frameworks mandan megabytes de JS al navegador, Astro entrega principalmente HTML. Las páginas cargan rápido por sí solas, sin un plugin de caché haciendo el trabajo pesado.

Cronología de versiones, para que sepas dónde estás (verificado oct 2026): Astro 5 salió en dic 2024, Astro 6 aterrizó en mar 2026, y **Astro 7** llegó el 22 de junio de 2026 con un compilador basado en Rust. La versión actual es 7.3.8 (8 de octubre de 2026). El tema de esta guía corre Astro 7.

### Por qué Astro es perfecto para tu blog

- HTML estático y cero JS por defecto: tus páginas son archivos simples en una CDN, que es lo que quieren los buscadores y los móviles lentos
- Arquitectura de islas: solo se hidratan las partes interactivas
- Usa cualquier framework de UI que te guste, o ninguno
- Soporte de Markdown para escribir posts
- Valores por defecto sin configuración, para que pases el tiempo escribiendo en vez de cableando

Piensa en Astro como el mullet de los frameworks web: negocios delante (HTML estático para velocidad) y fiesta detrás (JavaScript solo donde lo necesitas). Hoy lo usamos para construirte un blog que no necesita un niñero de devops. ¿Ya tienes un sitio WordPress? Mira [cómo migré mi sitio WordPress a Astro](/es/migracion-wordpress-a-astro/) — fue mucho menos doloroso de lo que esperaba.

---

## Lo que tendrás al final

Todo el **stack de $0: GitHub + Astro + Cloudflare Pages**. Esto es lo que obtienes:

<ListCheck>
<ul>
<li>Un blog moderno y responsive impulsado por Astro</li>
<li>Contenido guardado en un repo de GitHub que controlas</li>
<li>Sitio desplegado en Cloudflare Pages con SSL gratis</li>
<li>Una URL `*.pages.dev` gratis, más un dominio propio opcional (porque `mibloggenial.com` supera a `cadenaaleatoria.pages.dev`)</li>
<li>Despliegues de preview gratis por cada rama, que hacen las veces de staging</li>
<li>Coste total: **$0.00**</li>
</ul>
</ListCheck>

---

## Lo que necesitas

<ListCheck>
<ul>
<li>Una cuenta de GitHub (gratis, la crearás en el Nivel 1)</li>
<li>Node.js **v22.12.0 o más nuevo** y npm **10.8.2+** (suelo duro: el tema y Astro 7 se niegan a correr por debajo de esto; el LTS actual 24.x es perfecto)</li>
<li>git (incluido con VS Code, Xcode Command Line Tools, o el gestor de paquetes de tu distro)</li>
<li>Conocimientos básicos de Markdown</li>
<li>Unos 30 minutos</li>
<li>Visual Studio Code o cualquier editor (opcional)</li>
<li>Una bebida a tu elección</li>
</ul>
</ListCheck>

Comprobación rápida antes de cualquier otra cosa:

```bash
node --version   # expect v22.12.0 or newer, e.g. v22.23.3 or v24.22.0
npm --version    # expect 10.8.2 or newer
```

Si `node --version` imprime algo por debajo de v22.12.0, para aquí y actualiza. Astro 7 no correrá en Node más viejo, y solo coleccionarás errores de engine en el Nivel 6. La solución completa está en la sección de Resolución de problemas al final.

---

<YouTubeEmbed
  url="https://www.youtube.com/embed/EMLuT8YN8Xs"
  label="Cómo Crear un Blog Gratis con Astro y Cloudflare en 30 Minutos"
/>

*Aviso: el vídeo es anterior a Astro 7, al renombrado del dashboard de Cloudflare (Workers & Pages) y a la división de config `site.ts`. Es genial para el flujo general, pero sigue los pasos escritos de abajo donde la UI o los archivos de config se hayan movido.*

## Nivel 1: hazte GitHubber (5 minutos)

¿Ya tienes cuenta de GitHub? Salta adelante.
Si no:

1. Ve a [GitHub.com](https://github.com)
2. Haz clic en **Sign up**
3. Elige un nombre de usuario
4. Verifica tu email (revisa el spam, esos correos escurridizos adoran esconderse)

**Logro desbloqueado:** tienes una cuenta de GitHub.

**Verifica:** estás logueado y puedes ver tu dashboard en `github.com`.

<Notice type="info" title="¿Prefieres SSH?">
El clonado por HTTPS funciona bien para esta guía. Si prefieres usar claves desde el principio: [vincula GitHub con SSH en Mac/Linux](/link-github-with-ssh-maco-linux/).
</Notice>

---

## Nivel 2: Node tu camino al éxito (5 minutos)

Antes de ponernos a programar, instala Node.js y npm:

1. Visita [nodejs.org](https://nodejs.org/)
2. Descarga la versión **LTS** (24.x a octubre de 2026; cualquier cosa v22.12.0+ funciona)
3. Instálala como cualquier otra app
4. Abre Terminal/Símbolo del sistema y escribe:

```bash
node --version   # expect v22.12.0 or newer (Astro 7 requirement)
npm --version    # expect 10.8.2 or newer
```

Si ves números en el rango correcto, vas bien. Si ves números en el rango *incorrecto* (`v18.x`, `v20.x`), ahora posees un modo de fallo conocido: `npm install` lanzará errores de engine y el servidor de dev se negará a arrancar. Arréglalo antes de seguir.

Para los curiosos: Node 26 se convierte en LTS el 28-10-2026. No necesitas perseguir la versión más nueva, solo necesitas superar el suelo de v22.12.0.

<Notice type="info" title="Para más sobre Node.js">
Varias versiones en una máquina, sin dramas de sudo: [instala Node.js con nvm en macOS/Ubuntu](/install-nodejs-using-nvm-macos-ubuntu/).
</Notice>

---

## Nivel 3: poténciate con VS Code (opcional, 3 minutos)

Porque programar en el Bloc de notas es muy de 1995.

1. Ve a [code.visualstudio.com](https://code.visualstudio.com/)
2. Descarga e instala
3. Ábrelo

Cualquier editor vale: Neovim, Windsurf, lo que ya tengas abierto. VS Code es simplemente el camino de menor resistencia aquí porque su panel git integrado hace los pasos del Nivel 5 y el Nivel 9 sin salir de la ventana. Si quieres un editor de código con IA como [Windsurf](https://go.bitdoze.com/windsurf), también funciona.

---

## Nivel 4: haz fork de un tema de blog Astro gratis (2 minutos)

Hora de coger la plantilla del blog. Esta es toda la razón por la que la guía funciona: un tema de blog Astro gratis con búsqueda, RSS, modo oscuro y unos 20 posts de demo ya cableados.

1. Visita [Bitdoze Astro Theme](https://github.com/bitdoze/bitdoze-astro-theme)
2. Pulsa **Fork** (esquina superior derecha)
3. Nómbralo como quieras (`my-awesome-blog` funciona)
4. Haz clic en **Create fork**

Ahora posees una copia.

<Notice type="info" title="¿Dónde está el botón 'Use this template'?">
El README del tema menciona el atajo "Use this template" de GitHub, pero el repo no está marcado actualmente como plantilla de GitHub, así que ese botón puede no aparecer. No lo busques. **Fork** es el camino fiable (y mantiene funcionando el flujo de merge con upstream de "Mantén tu blog fresco"). Si odias los forks, usa el Método B de abajo.
</Notice>

<Tabs>
<Tab name="Método A: Fork (recomendado)">

Exactamente los 4 pasos de arriba. Tu fork vive en `github.com/TU-USUARIO/my-awesome-blog`, y **Sync fork** en GitHub lo mantiene al día con el tema.

</Tab>
<Tab name="Método B: Clonar + push a un repo nuevo">

Para cuando quieres un repo limpio sin relación de fork:

```bash
git clone https://github.com/bitdoze/bitdoze-astro-theme.git my-awesome-blog
cd my-awesome-blog
rm -rf .git
git init
git add .
git commit -m "Import Bitdoze Astro Theme"
```

Luego crea un repo vacío en GitHub y haz push:

```bash
git remote add origin https://github.com/YOUR-USER/my-awesome-blog.git
git push -u origin main
```

**Verifica:** `git remote -v` muestra tu repo como `origin`.

</Tab>
</Tabs>

**Verifica:** el repo aparece bajo tu cuenta de GitHub con los archivos del tema dentro.

---

## Nivel 5: clona como un pro (3 minutos)

Pon el código en tu máquina:

1. En tu repo forkeado, haz clic en **Code** > copia la URL HTTPS
2. Abre VS Code
3. Pulsa `Ctrl+Shift+P` (o `Cmd+Shift+P` en Mac)
4. Escribe **Git: Clone**, pulsa Enter
5. Pega la URL, elige una carpeta
6. Abre el repo cuando te lo pida

**Verifica:** la carpeta del repo se abre en VS Code con `package.json` visible en el árbol de archivos. ¿No hay `package.json`? Clonaste la cosa equivocada.

---

## Nivel 6: instala y corre en local (5 minutos)

Conecta las tuberías y pon el blog corriendo en tu propia máquina.

1. Abre la terminal en VS Code (`Ctrl + backtick`)
2. Escribe:

```bash
npm install
npm run dev
```

3. Espera la instalación (la primera ejecución descarga el toolchain de Astro)
4. Visita `http://localhost:4321`

Dato curioso: el repo trae un archivo `.node-version` fijado a `22.12.0`. Eso es lo que mantiene a todos en el mismo suelo de Node, aquí y luego en Cloudflare.

**Logro desbloqueado:** el blog corre en tu máquina.

**Verifica:** `http://localhost:4321` muestra la página de inicio de demo: sección hero más una rejilla de posts de demo. Es el contenido de ejemplo del tema, lo desalojaremos en un minuto.

**Roto se ve así:** la terminal da errores al arrancar. Nueve de cada diez veces es Node más viejo que v22.12.0 o un `node_modules` rancio. Salta a Resolución de problemas al final de esta guía.

---

## Nivel 7: hazlo tuyo (10 minutos)

Añade tu toque personal. Esta es la sección que más cambió en la actualización del tema de 2026, así que lee los nombres de archivo con cuidado. Antiguamente todo vivía en `config.json`. Ya no.
<svg viewBox="0 0 900 320" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Theme config map: site.ts holds identity, hero, and homepage toggles. config.json holds the contact form endpoint and contact info. menu.json holds navigation links. social.json holds social links. src/content/posts/ holds your articles.">
  <title>Theme config map: what to edit where</title>
  <rect x="0" y="0" width="900" height="320" fill="#f8fafc" rx="8"></rect>
  <text x="450" y="30" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="16" font-weight="600" fill="#0f172a">Theme config map: what to edit where</text>
  <rect x="40" y="55" width="390" height="85" rx="8" fill="#e0f2fe" stroke="#0284c7" stroke-width="2"></rect>
  <text x="235" y="88" text-anchor="middle" font-family="ui-monospace, monospace" font-size="14" font-weight="600" fill="#0c4a6e">src/config/site.ts</text>
  <text x="235" y="112" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12" fill="#0c4a6e">identity, hero, homepage toggles</text>
  <rect x="470" y="55" width="390" height="85" rx="8" fill="#fef3c7" stroke="#d97706" stroke-width="2"></rect>
  <text x="665" y="88" text-anchor="middle" font-family="ui-monospace, monospace" font-size="14" font-weight="600" fill="#92400e">src/config/config.json</text>
  <text x="665" y="112" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12" fill="#92400e">contact form endpoint + contact info only</text>
  <rect x="40" y="165" width="390" height="75" rx="8" fill="#ecfdf5" stroke="#059669" stroke-width="2"></rect>
  <text x="235" y="195" text-anchor="middle" font-family="ui-monospace, monospace" font-size="14" font-weight="600" fill="#065f46">src/config/menu.json</text>
  <text x="235" y="218" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12" fill="#065f46">navigation links</text>
  <rect x="470" y="165" width="390" height="75" rx="8" fill="#f3e8ff" stroke="#7c3aed" stroke-width="2"></rect>
  <text x="665" y="195" text-anchor="middle" font-family="ui-monospace, monospace" font-size="14" font-weight="600" fill="#5b21b6">src/config/social.json</text>
  <text x="665" y="218" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12" fill="#5b21b6">social links</text>
  <rect x="255" y="262" width="390" height="45" rx="8" fill="#e2e8f0" stroke="#475569" stroke-width="2"></rect>
  <text x="450" y="290" text-anchor="middle" font-family="ui-monospace, monospace" font-size="13" font-weight="600" fill="#0f172a">src/content/posts/ : your articles</text>
</svg>

### Actualiza `src/config/site.ts` (la identidad de tu blog)

Este es ahora el único archivo de identidad. Edita los strings obvios, deja la estructura quieta:

```typescript
export const siteConfig = {
  // Identity
  title: "Your Amazing Blog Title",
  brandName: "Your Blog Name",
  logoText: "Your Blog Name",
  author: "Your Name",
  description: "Your captivating blog description",
  heroDescription: "One or two sentences under your hero headline.",
  footerDescription: "What your blog is about, in one line.",
  postsPerPage: 11,
  // Below this you'll find hero { title, titleAccent, primaryCta, ... }
  // and homepage { showFeaturedPosts, showTaxonomyCards, ... }
  // leave the rest alone for now
};
```

Nota para quien siga tutoriales viejos: **ya no hay clave `name`**. Si un post te dice que pongas `siteConfig.name`, está describiendo una versión muerta del tema. `title` y `brandName` son tus nuevas amigas.

### Actualiza `src/config/config.json` (solo cosas de contacto)

`config.json` ya no guarda el título ni la URL de tu sitio. Solo guarda el endpoint del formulario de contacto y los datos de contacto:

```json
{
  "params": {
    "contact_form_action": "#"
  },
  "contactinfo": {
    "address": "",
    "email": "you@example.com",
    "phone": ""
  }
}
```

Deja `contact_form_action` como `"#"` hasta que tengas un endpoint de formulario, luego [añade un formulario de contacto a Astro gratis, sin backend](/add-contact-form-astro/) y apunta el action a tu endpoint.

### Menús y redes sociales (sin cambios)

La navegación vive en `src/config/menu.json` y los iconos sociales viven en `src/config/social.json`, igual que en la guía vieja. Las rutas y las formas están en "Personaliza aún más" más abajo si las necesitas.

<Notice type="info" title="El modelo mental de una línea">
`site.ts` = identidad · `config.json` = contacto · `menu.json` = nav · `social.json` = redes. Ten esto claro y el tema nunca te peleará.
</Notice>

**Verifica:** con `npm run dev` aún corriendo, cambia `title` y `brandName` en `site.ts`, guarda, y haz hard-refresh de `http://localhost:4321`. El texto del hero/footer debería cambiar. Si el servidor de dev lanza un error de TypeScript, probablemente quitaste una coma o una comilla — la línea del error apunta justo ahí.

---

## Nivel 7.5: desaloja el contenido de demo (2 minutos)

El tema trae unos 20 posts de demo y un par de autores de demo. Salta este paso y tu primer despliegue estará lleno de artículos de otra persona. El README es directo al respecto: borra lo que no necesites.

1. Abre `src/content/posts/`
2. Borra los archivos `.md`/`.mdx` de demo (guarda uno hasta la prueba de humo si quieres algo en lo que clicar)
3. Revisa `src/content/authors/` y `src/content/about/index.md` por texto de demo que quieras reemplazar

Buenas noticias: las colecciones vacías se renderizan como listas vacías. Borrarlo todo **no** rompe el build.

**Verifica:** refresca `http://localhost:4321`, la página de inicio muestra solo tu contenido (o estados vacíos limpios).

---

## Nivel 8: escribe tu primer post (5 minutos)

1. Ve a `src/content/posts/`
2. Crea `my-first-post.md`
3. Pega esto dentro:

```markdown
---
title: "My First Blog Post"
meta_title: "My First Amazing Blog Post"
description: "This is the beginning of my blogging journey!"
date: 2023-07-15
image: "../../assets/images/web-development.svg"
authors: ["admin"]
categories: ["Personal"]
tags: ["beginnings", "blogging"]
featured: true
---

## Hello World!

Welcome to my shiny new blog! I'm excited to overshare my thoughts with the internet.

### Why I Started This Blog

- To rant
- To teach
- To learn
- To procrastinate productively

Stay tuned for more!

![Celebration](https://media.giphy.com/media/3o6fJ1BM7R2EBRDnxK/giphy.gif)
```

Dos notas de frontmatter. Primero, `featured: true` (opcional) saca el post en la rejilla "Featured Posts" de la página de inicio, así que úsalo para tu mejor material. Segundo, sobre las rutas de imágenes: el esquema de contenido se volvió más estricto en la actualización de 2026. En vez de fiarte de cualquier ruta que veas en un tutorial (incluida la de arriba), copia la línea `image:` de uno de los posts de demo que aún no hayas borrado, y apúntala a una imagen que hayas añadido de verdad. Con una ruta mala obtienes una imagen rota o un error de build, no una pista amigable.

4. Guarda y refresca `http://localhost:4321`

**Logro desbloqueado:** primer post publicado.

**Verifica:** el post aparece en la página de inicio *y* se abre en su propia página. ¿Quieres medios en tus posts más adelante? Aquí está [cómo añadir vídeos de YouTube a tu blog Astro](/add-youtube-videos-astro-blog/).

**Roto se ve así:** un error mencionando una etiqueta sin cerrar o HTML inválido. Astro 7 se volvió más estricto, el HTML pegado ahora hace fallar el build en vez de arreglarse silenciosamente. Mira la sección de Resolución de problemas al final.

---

## Nivel 9: guarda y haz push (2 minutos)

1. Haz clic en el icono de Source Control (el coso con ramas)
2. Prepara todos los cambios (botón +)
3. Escribe un mensaje de commit
4. Haz clic en la marca de verificación para commitear
5. Haz push vía el menú "..." > **Push**

<Notice type="warning" title="Construye en local antes de hacer push">
Las reglas HTML más estrictas de Astro 7 significan que las etiquetas sin cerrar y los atributos sin terminar ahora **hacen fallar el build** en vez de autocorregirse. El error imprime archivo + línea, mucho más amigable en tu máquina que en un log de build de Cloudflare. Ejecuta `npm run build` (o el doble seguro `npm run verify`) antes de cada push. Tarda segundos en un blog recién creado.
</Notice>

**Verifica:** `npm run build` termina limpio e imprime la carpeta `dist/`. Si no, el último error en la terminal te dice qué archivo abrir.

---

## Nivel 10: entra en la nube (3 minutos)

1. Regístrate en [Cloudflare.com](https://dash.cloudflare.com/sign-up)
2. Verifica el email
3. Salta "Add a website" (estamos haciendo Pages, aún no hace falta dominio)

No hace falta tarjeta para nada de esto. Pages Free es genuinamente gratis.

---

## Jefe Final: despliega tu blog Astro en Cloudflare Pages (5 minutos)

Aquí está todo el pipeline en una imagen: un `git push` se convierte en un blog en vivo.
<svg viewBox="0 0 900 210" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="How a git push becomes a live blog: local commit goes to GitHub main, Cloudflare Pages builds with Node 22.12 pinned by .node-version, emits the dist folder as static output, and serves it on a pages.dev URL with free SSL. Any other branch becomes a free preview deployment.">
  <title>How a git push becomes a live blog</title>
  <rect x="0" y="0" width="900" height="210" fill="#f8fafc" rx="8"></rect>
  <text x="450" y="30" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="16" font-weight="600" fill="#0f172a">How a git push becomes a live blog</text>
  <rect x="20" y="55" width="150" height="85" rx="8" fill="#e0f2fe" stroke="#0284c7" stroke-width="2"></rect>
  <text x="95" y="90" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="13" font-weight="600" fill="#0c4a6e">git push</text>
  <text x="95" y="112" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="11" fill="#0c4a6e">your machine</text>
  <line x1="172" y1="97" x2="192" y2="97" stroke="#2563eb" stroke-width="2"></line>
  <polygon points="192,91 204,97 192,103" fill="#2563eb"></polygon>
  <rect x="206" y="55" width="150" height="85" rx="8" fill="#e0f2fe" stroke="#0284c7" stroke-width="2"></rect>
  <text x="281" y="90" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="13" font-weight="600" fill="#0c4a6e">GitHub</text>
  <text x="281" y="112" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="11" fill="#0c4a6e">main branch</text>
  <line x1="358" y1="97" x2="378" y2="97" stroke="#2563eb" stroke-width="2"></line>
  <polygon points="378,91 390,97 378,103" fill="#2563eb"></polygon>
  <rect x="392" y="55" width="150" height="85" rx="8" fill="#fef3c7" stroke="#d97706" stroke-width="2"></rect>
  <text x="467" y="82" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="13" font-weight="600" fill="#92400e">Pages build</text>
  <text x="467" y="102" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="11" fill="#92400e">Node 22.12</text>
  <text x="467" y="120" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="11" fill="#92400e">via .node-version</text>
  <line x1="544" y1="97" x2="564" y2="97" stroke="#2563eb" stroke-width="2"></line>
  <polygon points="564,91 576,97 564,103" fill="#2563eb"></polygon>
  <rect x="578" y="55" width="130" height="85" rx="8" fill="#ecfdf5" stroke="#059669" stroke-width="2"></rect>
  <text x="643" y="90" text-anchor="middle" font-family="ui-monospace, monospace" font-size="13" font-weight="600" fill="#065f46">dist/</text>
  <text x="643" y="112" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="11" fill="#065f46">static output</text>
  <line x1="710" y1="97" x2="730" y2="97" stroke="#2563eb" stroke-width="2"></line>
  <polygon points="730,91 742,97 730,103" fill="#2563eb"></polygon>
  <rect x="744" y="55" width="136" height="85" rx="8" fill="#e2e8f0" stroke="#475569" stroke-width="2"></rect>
  <text x="812" y="90" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12" font-weight="600" fill="#0f172a">*.pages.dev</text>
  <text x="812" y="112" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="11" fill="#0f172a">free SSL</text>
  <text x="450" y="185" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12" fill="#475569">Any other branch you push becomes a free preview deployment (unlimited on the free plan).</text>
</svg>

El nav del dashboard cambió en 2026, así que sigue esto exactamente:

1. Dashboard de Cloudflare → **Workers & Pages**
2. **Create application** → pestaña **Pages** → **Connect to Git**
3. Autoriza GitHub, elige tu fork
4. Pon el nombre del proyecto (`my-awesome-blog` funciona) y la rama de producción: **`main`**
5. Framework preset: **Astro** (o configura manualmente): Build command **`npm run build`**, Output directory **`dist`**
6. Haz clic en **Save and Deploy**

Hora del café mientras Cloudflare construye.

Dos trampas que conviene conocer antes de clicar:

- Un proyecto integrado con Git **no puede** cambiarse a Direct Upload después. Elige Git (lo hicimos) y estás bien.
- Cada rama que no sea `main` se convierte en su propio **despliegue de preview** con una URL única. Es staging gratis, úsalo sin vergüenza.

<Notice type="info" title="¿Ves un empujón de 'Use Workers instead?'">
Esperado. Cloudflare ahora dirige los proyectos nuevos hacia Workers y los docs de Pages llevan un banner diciéndolo. Para un blog estático, Pages sigue siendo gratis, sigue soportado, y es lo que corre este mismo sitio. Si algún día se te queda pequeño, Cloudflare publica un doc "Migrate to Workers". No has tomado un desvío equivocado.
</Notice>

<Notice type="info" title="Plan gratis, cifras reales">
Cloudflare Pages Free (página de límites actualizada el 05-09-2026): **500 builds/mes**, **1 build concurrente**, **timeout de build de 20 minutos**, **20.000 archivos**, **25 MiB tamaño máximo de archivo**, **100 dominios personalizados por proyecto**, **despliegues de preview ilimitados**. Un blog personal ni se registra en esos medidores. La clásica redacción de "ancho de banda y peticiones ilimitadas" vive en la página de precios — compruébalo ahí antes de citarlo con seguridad.
</Notice>

**Verifica:** el log de build se pone verde y Cloudflare te da una URL tipo `https://my-awesome-blog.pages.dev`. Ábrela.

**Roto se ve así:** un build fallido por un comando de build mal tecleado o un directorio de salida equivocado (es `npm run build` y `dist`), o los errores de versión de Node cubiertos en Resolución de problemas. El timeout de 20 minutos no morderá a un blog de este tamaño.

Para la versión más larga y llena de capturas de este flujo de despliegue, mira [nuestra guía completa de despliegue de un blog Astro en Cloudflare](/deploy-astrojs-cloudflare/).

---

## La prueba de humo de 5 minutos (tras tu primer despliegue)

No te limites a admirar la URL. Pínchala. Esta es la checklist de "¿funcionó de verdad?":

<ListCheck>
<ul>
<li>Abre la URL `*.pages.dev`: página de inicio, una página de post y una página de categoría se renderizan</li>
<li>La búsqueda del sitio (el tema trae búsqueda de cliente con Fuse.js) devuelve tu post</li>
<li>`/rss.xml` carga y existe un sitemap</li>
<li>Una URL basura como `/this-does-not-exist` renderiza tu página 404 personalizada</li>
<li>Haz push de una rama desechable y coge la URL de su **despliegue de preview** gratis en la pestaña Deployments</li>
<li>Si algo se ve raro, ejecuta `npm run build` o `npm run verify` en local primero — el error es más claro ahí</li>
</ul>
</ListCheck>

Esos despliegues de preview son tu entorno de staging gratuito. Úsalos para ediciones arriesgadas del tema antes de mergear a `main`.

---

## Ronda Bonus: dominio personalizado (opcional, 5 minutos)

1. Compra un dominio. ¿Necesitas primero una comprobación de naming? Aquí está [cómo elegir un buen nombre de dominio](/choose-domain-name/).
2. En Cloudflare Pages, abre tu proyecto > **Custom domains**
3. Haz clic en **Set up a custom domain**
4. Sigue las instrucciones de DNS

El SSL sigue siendo gratis en ambos casos, Cloudflare emite y renueva el certificado por ti.

Sobre el precio: salta la fantasía de "$1/año" salvo que disfrutes de las sorpresas de renovación. La opción aburrida y predecible es **Cloudflare Registrar**: dominios a precio de coste, aproximadamente el precio mayorista, sin juegos de renovación con recargo. Mira su página de registrar para la cifra actual, no fijaré una aquí.

**Verifica:** `https://tudominio.com` carga con el candado, y el código fuente de la página muestra tu dominio (no `pages.dev`) en la etiqueta canonical.

### Apunta `SITE_URL` a tu dominio de producción

Una vez que el dominio personalizado funciona, el README del tema te dice que apuntes `SITE_URL` a tu origen de producción para que las URLs canonical, las etiquetas Open Graph y el sitemap dejen de anunciar tu dirección `*.pages.dev`.

<Notice type="warning" title="Verifica antes de copiar">
Comprueba el paso `SITE_URL` del README del tema para el mecanismo actual (variable de entorno en los ajustes de build de Pages vs un campo de config) antes de editar nada — se ha movido entre versiones del tema. La versión segura de esta instrucción: encuentra `SITE_URL` en el README, ponlo a `https://tudominio.com`, redespliega, y confirma la etiqueta canonical de nuevo.
</Notice>

---

## Lo que cuesta todo esto

| Pieza | Coste |
|---|---|
| Cuenta de GitHub + repos | $0 |
| Astro (open source, MIT) | $0 |
| Cloudflare Pages, plan Free | $0 (500 builds/mes, previews ilimitados) |
| Certificado SSL | $0 (gestionado por Cloudflare) |
| URL `*.pages.dev` | $0 |
| Dominio personalizado (opcional) | ~$10/año a precio de coste vía Cloudflare Registrar (los TLDs en promo pueden ser más baratos) |
| **Total tal como está escrito** | **$0.00** |

El dominio es vanidad, no necesidad. Muchos buenos blogs viven en una URL `pages.dev` para siempre.

---

## Sigue blogueando como un campeón

### Opción 1: editar en GitHub

- Añade archivos `.md` en `src/content/posts/`
- Commitea los cambios
- Listo

Útil desde una tablet en el sofá. Solo recuerda que las reglas HTML más estrictas de Astro 7 aplican en cada push, así que escribe Markdown limpio.

### Opción 2: editar en local (recomendado)

1. Trae lo último:

```bash
git pull
```

2. Añade el post nuevo
3. Previsualiza con:

```bash
npm run dev
```

4. Commitea y haz push:

```bash
git add .
git commit -m "Add awesome new post"
git push
```

Cloudflare redesplegará automáticamente.

**Verifica:** la pestaña **Deployments** del proyecto en Cloudflare muestra el nuevo build, y el post está en vivo en tu URL.

¿Creciendo más allá de un puñado de archivos Markdown? Cuando el flujo de `git pull` empiece a sentirse como una tarea para editores no técnicos, mira las [mejores opciones de headless CMS para Astro](/best-headless-cms-for-astro/). Y si quieres lectores, haz crecer una audiencia con una herramienta de newsletter de nivel gratuito como [EmailOctopus](https://go.bitdoze.com/emailoctopus) — encaja con el tema de $0 de toda esta operación.

---

## Consejos pro

- Publica con regularidad
- Usa imágenes y GIFs para romper el texto
- Comparte tus posts donde están tus lectores, y responde a los comentarios
- Marca tus mejores posts con `featured: true` para que la rejilla de la página de inicio te haga justicia
- Haz de `npm run verify` tu reflejo pre-push: tipos comprobados, tests ejecutados, build en verde
- Si quieres estadísticas sin la economía de la vigilancia, corre [analítica Plausible respetuosa con la privacidad en Cloudflare Workers](/astro-plausible-cloudflare-workers/)

Bloguear no debería sentirse como deberes. Si lo hace, publica menos a menudo en vez de abandonar.

---

## Chuleta del flujo de dev local

```bash
npm run dev        # Start local server (http://localhost:4321)
npm run build      # Build production version into dist/
npm run preview    # Preview the production build
npm run verify     # astro check + tests + build (safe pre-push habit)
git add .          # Stage changes
git commit -m "Your message"  # Commit
git push           # Deploy!
```

---

## Personaliza aún más

Tu proyecto es flexible. Esto es lo que puedes retocar dentro de la carpeta `src/`:

### Estilos y colores

- Edita `src/styles/global.css` para cambiar los colores del tema, las fuentes o añadir CSS personalizado.

```css
:root {
  --color-primary-500: #3b82f6; /* Change this to your fav color */
}
```

- Personaliza los colores del modo oscuro bajo `.dark { ... }` en el mismo archivo.

### Enlaces sociales

- `src/config/social.json` guarda las URLs de tus perfiles sociales (mira el Nivel 7 para el mapa de archivos).

### Menú de navegación

- `src/config/menu.json` personaliza los enlaces de navegación de tu sitio.

### Imágenes, logos y favicons

- Pon las imágenes en `src/assets/images/` o `public/images/` (la primera se optimiza en el build, la segunda se copia tal cual).
- Reemplaza favicons/logos en `src/assets/favicons/` o `public/`.
- Actualiza las referencias si hace falta en configs o archivos de layout.

### Contenido: posts, páginas, autores

- Los posts del blog viven en `src/content/posts/`
- Las páginas estáticas viven en `src/content/pages/` (p. ej., Privacidad, Términos)
- La página de "about" es `src/content/about/index.md`
- Los perfiles de autor viven en `src/content/authors/`, genial para blogs multi-autor

### Información del sitio y metadatos

- `src/config/site.ts` es el archivo de identidad: título, marca, texto del hero, toggles de la página de inicio (Nivel 7).
- `src/config/config.json` es solo de contacto: endpoint del formulario más datos de contacto (Nivel 7).

### Layouts y componentes

- Personaliza cómo se ve tu blog editando los componentes en `src/layouts/` y sus subcarpetas.
- Cambia headers, footers, layouts de post, widgets, etc.

### Páginas y enrutado

- Añade o edita páginas en `src/pages/` (p. ej., `/about`, `/contact`, `/blog`).
- Crea nuevos archivos `.astro` para rutas personalizadas.

---

Así puedes personalizar completamente el aspecto, la sensación y el contenido de tu blog.

## Mantén tu blog fresco

1. Añade el repo original como upstream:

```bash
git remote add upstream https://github.com/bitdoze/bitdoze-astro-theme.git
```

2. Trae las actualizaciones:

```bash
git fetch upstream
```

3. Mergea:

```bash
git merge upstream/main
```

4. ¡Arregla conflictos, haz push, y listo!

**Lee el `CHANGELOG.md` del tema antes de mergear una nueva versión de upstream.** Es la diferencia entre "ah, esa clave se movió" y una tarde confusa de arqueología. La rama por defecto sigue siendo `main`.

**¿Conflictos de merge en `site.ts` o `config.json`?** Normalmente significa que upstream renombró o dividió una clave de config. El changelog te dice la nueva forma, luego reaplica tus valores encima.

---

## "¿Pero por qué Astro?" (para los escépticos)

"¿No podría simplemente usar WordPress/Wix/Medium?" Claro, también podrías usar un cuchillo de untar para talar un árbol. Aquí está el caso honesto, con cifras incluidas:

- El compilador Rust de Astro 7 construyó las 743 páginas de este mismo blog en 47s, bajando de 103s en Astro 6. Ese es el [benchmark de Astro 7: tiempos de build reducidos a la mitad en un sitio de 743 páginas](/astro-7-faster-builds/). Para un blog de diez posts, los builds son instantáneos de todas formas — el punto es que el tooling crece contigo.
- La velocidad que sienten tus lectores viene del HTML estático y el cero JS por defecto. Tus páginas son archivos servidos desde una CDN. Nada que parchear, ningún PHP que seguir actualizando, ningún plugin de caché haciendo heroicidades.
- Coste y operaciones se quedan aburridos: $0 al mes y las únicas piezas móviles son git y un build. Compara eso con planes de builders gestionados o un host de WordPress con staging, backups y una suscripción a plugin de seguridad.
- Un sitio estático es una superficie de ataque diminuta, pero sigues siendo dueño de la seguridad de tu cuenta de GitHub (activa 2FA) y de las actualizaciones de dependencias vía merges de upstream. Nada es "configura y olvida".
- WordPress ES la elección correcta para ecosistemas de plugins pesados, varios editores no técnicos, o una tienda con necesidades reales de e-commerce. Si ese eres tú, lee [un desglose honesto de costes y operaciones de Astro vs WordPress](/astro-vs-wordpress/) antes de comprometerte a nada.

Construirlo tú mismo también significa que puedes decir "ah, ¿mi blog? Lo construí con Astro" en las fiestas, si te va eso.

---

## Resolución de problemas

### ¿El sitio no construye?

- Revisa los errores de la terminal
- Valida la sintaxis Markdown
- Ejecuta `npm run build` en local para pistas

### El build falla con "unclosed tag" o HTML inválido

Astro 7 dejó de autocorregir markup roto. Las etiquetas sin cerrar y los atributos sin terminar ahora **hacen fallar el build**, y el error imprime el archivo y el número de línea.

- **Solución:** abre ese archivo, cierra la etiqueta (o termina el atributo), ejecuta `npm run build` en local, haz push de nuevo. Pegar HTML de la web es el culpable habitual.

### Funciona en local, falla en Cloudflare

Si el build se pone verde en tu máquina y rojo en el log de Cloudflare, comprueba la versión de Node en el host de build. El tema trae `.node-version` fijado a `22.12.0` y la imagen de build de Cloudflare lo lee automáticamente.

- **Solución:** si moviste el tema a tu propio repo, conserva el archivo `.node-version`. Si no puedes, pon `NODE_VERSION=22.16.0` (o cualquier 22.12+) en las variables de entorno de build del proyecto Pages.

### npm install falla o lanza errores de engine

¿Ves `EBADENGINE` o "unsupported engine"? Tu Node está por debajo del suelo de v22.12.0.

- **Solución:** comprueba `node --version`, actualiza Node ([guía de nvm aquí](/install-nodejs-using-nvm-macos-ubuntu/)), luego:

```bash
npm cache clean --force
```

- Borra `node_modules` y `package-lock.json`, reinstala.

### ¿Faltan imágenes?

- Comprueba las rutas
- Usa rutas relativas o URLs completas
- Pon las imágenes en `public/images/`

### El botón "Use this template" no aparece en GitHub

El repo del tema no está marcado como plantilla de GitHub, así que el botón a menudo no se renderiza. Usa **Fork** (Nivel 4, Método A) o la ruta de clonar-y-push (Método B).

### ¿Todo explotó?

Respira hondo. Lee el último error del log de build, comprueba la versión de Node, y reconstruye en local. Esos tres atrapan casi todo. Si sigue roto, los issues de GitHub del tema son el lugar correcto para preguntar.

---

## FAQ rápido

<Accordion label="¿Es esto realmente 100% gratis?" group="faq" expanded="true">
Sí, tal como está escrito. GitHub $0, Astro $0, Cloudflare Pages $0 (500 builds/mes, despliegues de preview ilimitados), SSL $0. El único coste posible es un dominio personalizado, y hasta eso es opcional. Desglose completo en "Lo que cuesta todo esto" más arriba.
</Accordion>

<Accordion label="Cloudflare me sigue diciendo que use Workers. ¿Elegí mal?" group="faq">
No. Cloudflare ahora dirige los proyectos nuevos hacia Workers porque es su plataforma más amplia, pero Pages sigue siendo gratis, sigue documentado, y sigue siendo en lo que corre este sitio. Para un blog estático, Pages hace el trabajo. Si tus necesidades algún día lo superan, hay un camino de migración documentado a Workers — no es un callejón sin salida.
</Accordion>

<Accordion label="¿Necesito saber React, Vue o algún framework?" group="faq">
No. Este tema es Astro a pelo más Markdown. Escribes posts en Markdown, el tema los convierte en HTML. Los frameworks son opcionales en Astro y aquí no se usan.
</Accordion>

<Accordion label="¿Puedo usar mi propio dominio?" group="faq">
Sí, y el SSL es gratis en ambos casos. Mira la Ronda Bonus para los pasos del dominio personalizado y la nota sobre apuntar `SITE_URL` a tu dominio de producción. Para el registro, Cloudflare Registrar vende dominios a precio de coste sin recargos de renovación.
</Accordion>

<Accordion label="¿Cómo añado comentarios, analítica, un formulario de contacto o vídeos?" group="faq">
El tema cubre búsqueda, RSS y modo oscuro nada más sacarlo. Para los extras: el endpoint del formulario de contacto te espera en `config.json` (Nivel 7), los embeds de medios están cubiertos en los enlaces del Nivel 8, y la sugerencia de analítica está en Consejos pro. Los tres tienen guías paso a paso dedicadas en este sitio.
</Accordion>

---

## ¡Lo conseguiste!

Ahora posees un blog funcionando en Cloudflare Pages que cuesta $0 mantener. Los siguientes movimientos habituales: escribe posts en un calendario, conecta un dominio personalizado cuando tengas uno, y automatiza cualquier cosa que te encuentres repitiendo.

¿Quieres ir más profundo una vez que el hábito de bloguear pegue? Trabaja los [mejores cursos online de Astro.js](/best-astrojs-online-courses/), conecta dominios personalizados correctamente, o automatiza despliegues con GitHub Actions.

<Button text="Consigue el Bitdoze Astro Theme" link="https://github.com/bitdoze/bitdoze-astro-theme" variant="solid" color="blue" size="md" icon="arrow-right" />

¡Feliz blogging!

_P.D. Si esta guía te ayudó, compártela y dale una estrella al [Bitdoze Astro Theme](https://github.com/bitdoze/bitdoze-astro-theme) en GitHub._