Saltar al contenido
  • Claude Code

Así publiqué mi sitio en Cloudflare con IA por 5 dólares al mes

Y el tuyo podría costar 0. La migración desde AWS la hizo Claude Code en 43 minutos. El resto del día fue lo que una IA no debe hacer sola: pagar, crear tokens y tocar el DNS.

Emanuel · 14 min de lecturaFuncionó
En este post 11 secciones
  1. Cuánto cuesta, pieza por pieza
  2. Lo que vas a necesitar
  3. Paso 1: decidir con números, no con costumbre
  4. Paso 2: la migración, en local (43 minutos)
  5. Paso 3: lo que hice yo (y por qué no la IA)
  6. Paso 4: publicar con cada push
  7. Paso 5: pruebas y producción
  8. Lo que salió mal
  9. Resultados
  10. Lo que aprendí
  11. Hazlo tú: la lista completa

Este sitio corre completo en Cloudflare: el servidor de Next.js, la lista de testers en una base de datos, los correos de confirmación con su firma, la caché de las páginas, una tarea diaria que borra los datos vencidos, HTTPS y un sitio de pruebas con contraseña. Cada vez que subo un cambio a GitHub, se publica solo en unos 2 minutos. Todo eso me cuesta 5 dólares al mes, y en el primer día el panel marca 0,00 USD de uso facturable encima de esa cuota.

Hace dos días el plan era AWS. Lo cambiamos con Claude Code en un día, y aquí está todo para que hagas tu versión: lo que cuesta cada pieza, cuándo podría costarte 0, los prompts, los comandos y los errores, que fueron varios.

Panel de Workers de Cloudflare con dos aplicaciones, emanuelconia y emanuelconia-pruebas, y el uso del período: 0,00 USD facturables, 3,37 mil peticiones y 109,76 mil milisegundos de CPU.
Los dos Workers (producción y pruebas) y el uso del período: 3.370 peticiones, 0,00 USD facturables.

Cuánto cuesta, pieza por pieza

Lo primero que preguntas es el precio, así que va primero. Las cifras son de la documentación de Cloudflare del 20 de octubre de 2026; el uso es el de mi panel.

Cada pieza del sitio, para qué la uso y su costo
PiezaPara quéCosto
Workers (plan Paid)El servidor de Next.js, con el adaptador OpenNext5 USD al mes: incluye 10 millones de peticiones y 30 millones de ms de CPU
Archivos estáticosCSS, JavaScript, fuentes e imágenesGratis e ilimitados
D1La lista de testers (SQLite)Incluido: 25.000 millones de filas leídas al mes. Usé 398
R2 + Durable ObjectLa caché de las páginas que se regeneran solas10 GB gratis al mes. Uso 47 MB
Email ServiceConfirmación, bienvenida, códigos de beta3.000 correos al mes incluidos con el plan Paid
CronBorrar cada día los datos vencidosIncluido
DNS, CDN y HTTPSLos DNS, la red de Cloudflare y el certificadoGratis (plan Free del dominio)
Lista de suscripciones de la cuenta: Workers Paid, R2 Paid y Free Plan para emanuelconia.com.
Las suscripciones: Workers Paid (la cuota de 5 USD), R2 por uso y el plan Free del dominio.

¿Y el tuyo en 0?

Puede ser. El plan gratis de Workers da 100.000 peticiones al día, archivos estáticos sin límite, D1 con 5 millones de lecturas diarias y 5 GB, R2 con 10 GB y hasta 5 tareas programadas. Para un portafolio, un blog o una página de presentación, sobra.

Decidí pagar el plan de 5 USD por dos razones:

  • Los correos. Email Service solo envía a cualquier destinatario con el plan Paid. En el gratis, solo a direcciones que verificaste en tu cuenta.
  • El límite de CPU. El plan gratis da 10 ms de CPU por petición. Next.js renderizando en el servidor se pasa con facilidad, y la petición falla.

Los 5 USD alcanzan para varios proyectos

Los 5 USD son por cuenta, no por sitio. Con esa misma cuota puedes tener hasta 500 Workers, y todos comparten lo incluido: los 10 millones de peticiones, la base D1 y los 3.000 correos al mes. Yo ya tengo dos sitios ahí, producción y pruebas, y en el primer día usaron 3.370 peticiones de esos 10 millones. Si tus proyectos son pequeños, la misma cuota te sirve para publicar varios.

Lo que vas a necesitar

  • Una cuenta de Cloudflare (dash.cloudflare.com) con el DNS de tu dominio ahí. Email Service lo exige.
  • Claude Code (documentación) o el agente que uses para programar.
  • El MCP de Cloudflare, para que el agente busque en la documentación y revise tu cuenta.
  • wrangler, el CLI de Cloudflare. Se instala en el proyecto con pnpm add -D wrangler.
  • El adaptador OpenNext, si tu sitio es Next.js.
  • GitHub y su CLI gh, para que el despliegue sea automático.

El MCP de Cloudflare

Servidores MCP oficiales de Cloudflare: el agente busca en la documentación y usa la API de tu cuenta, con tu permiso por OAuth.

Lo usé para consultar precios y límites vigentes, y verificar lo que yo hacía en el panel.

  • TypeScript
  • 4,4 mil estrellas
  • Licencia Apache-2.0

Se agrega a Claude Code con un comando y se autoriza en el navegador:

Terminalzsh
claude mcp add --transport http cloudflare https://mcp.cloudflare.com/mcp
En la terminal. Después, /mcp dentro de Claude Code para autenticarte.

Me sirvió sobre todo para una cosa: leer la documentación del día. Ahí vimos que el correo exigía el plan Paid, antes de decidir. Los precios y límites cambian, y el agente no los sabe de memoria.

OpenNext para Cloudflare

Adaptador que convierte el resultado de next build en un Worker de Cloudflare: páginas en el servidor, ISR, middleware y archivos estáticos.

Lo usé para correr Next.js 16 en Workers sin reescribir el sitio.

  • TypeScript
  • 1,9 mil estrellas
  • Licencia MIT

Paso 1: decidir con números, no con costumbre

Yo conozco AWS, así que el plan era Amplify para el sitio, DynamoDB para la lista y SES para los correos. La noche antes de publicar pregunté qué cambiaría para usar Cloudflare. Al día siguiente lo comparamos con AWS y Vercel, y lo que decidió fue simple: el sitio todavía no estaba publicado, así que migrar costaba poco. Después habría costado mucho más.

Prompt1 · La decisión
Mi sitio Next.js todavía no está publicado. Compara hospedarlo en AWS, Vercel y Cloudflare Workers: costo mensual con poco tráfico, base de datos, envío de correos y despliegue automático. Usa la documentación vigente de cada uno (con el MCP de Cloudflare para la suya) y dime qué exige plan pago. Si recomiendas migrar, dime qué cambia en el código y qué tengo que hacer yo en los paneles.
Lo usé enClaude Code

Para el correo comparamos con lo que ya conocía. Ese día: Mailgun Basic cobraba 15 USD por 10.000 correos, Resend Pro 20 USD por 50.000 y SES 0,10 USD por 1.000. Email Service venía con 3.000 al mes dentro de los 5 USD que ya iba a pagar por Workers.

Paso 2: la migración, en local (43 minutos)

A las 11:53 dije «dale, haz la prueba en local con Cloudflare en una rama nueva». A las 12:36 estaba el commit: 47 archivos, 3.525 líneas nuevas y 913 borradas, con todo probado contra el Worker en mi máquina.

Prompt2 · Migración
En una rama nueva, migra el sitio a Cloudflare Workers con OpenNext. Cambia la base de datos por D1 (con migraciones SQL), el correo por Email Service y los secretos por wrangler secret. Configura dos entornos en wrangler.jsonc: pruebas (con contraseña y sin indexar) y producción. Prueba en local con el Worker real (pnpm cf:preview) el flujo completo: alta, confirmación por correo, votos, baja y límite de intentos. No publiques nada.
Lo usé enClaude Code
  1. Servidor

    Next.js en un Worker

    El adaptador OpenNext convierte el build en un Worker. Los archivos estáticos salen del mismo lugar, gratis.

  2. Datos

    DynamoDB → D1

    La lista pasó a SQLite con migraciones. Lo que vence se deja de leer y una tarea diaria lo borra.

  3. Correo

    SES → Email Service

    Un binding en el Worker. En local, los correos se imprimen en la terminal.

  4. Caché

    R2 + Durable Object

    Las páginas que se regeneran solas (las apps cada minuto, los posts cada día) se guardan en R2.

  5. Secretos

    wrangler secret

    Nada en .env ni en el build. Cada entorno tiene su clave.

  6. Publicar

    GitHub Actions

    Push a dev publica pruebas; push a main, producción.

Lo que cambió en esos 43 minutos.
Terminalzsh
$ pnpm cf:preview$ pnpm exec tsx e2e.mts http://localhost:8787✓ alta → 200 {"estado":"pendiente"}✓ confirmar → 303 /confirmado✓ cookie de sesión verificada✓ votos guardados✓ baja → 200✓ deshacer → 200✓ límite de intentos → 400 400 400 429 429 429 429Todo bien
La prueba contra el Worker local: el flujo completo de la lista (salida resumida).

Paso 3: lo que hice yo (y por qué no la IA)

Le pedí a Claude una guía paso a paso para hacer el setup yo, porque quería entender qué estaba creando. Hay cosas que una IA no debe hacer sola: pagar, crear tokens con permisos sobre tu cuenta y tocar el DNS. Yo hacía cada paso y Claude lo revisaba con la API.

  1. Activar Workers Paid y R2 en el panel. La tarjeta la pones tú.
  2. Arreglar el DNS del correo. Tenía dos registros SPF (uno viejo de Namecheap) y eso rompe la verificación. Dejé uno.
  3. Agregar el dominio a Email Service. Cloudflare crea sus registros MX, SPF y DKIM en un subdominio, sin tocar tu correo de siempre.
  4. Crear la base D1, la caché R2 y los secretos con wrangler.
  5. Crear un token de API para GitHub, con permisos solo para Workers, D1 y las rutas del dominio, y que vence en un año.
Terminalzsh
pnpm exec wrangler loginpnpm exec wrangler d1 create emanuelconia-pruebaspnpm exec wrangler d1 migrations apply DB --remote --env pruebaspnpm exec wrangler r2 bucket create emanuelconia-pruebas-cacheopenssl rand -hex 32 | pnpm exec wrangler secret put TOKENS_SECRETO --env pruebasgh secret set CLOUDFLARE_API_TOKENgh secret set CLOUDFLARE_ACCOUNT_ID
Los comandos del setup, para el entorno de pruebas.
  • Panel de D1 con dos bases, emanuelconia-produccion y emanuelconia-pruebas, y el uso: 398 filas leídas de 25 mil millones y 180 kB de 5 GB.D1 · la lista de testers
  • Panel de R2 con dos buckets de caché, de 12,5 MB y 34,66 MB, y 0,00 USD facturables.R2 · la caché de las páginas
  • Panel de Email Sending con emanuelconia.com activo, registros DNS configurados y 2 de 1.000 correos del cupo diario.Email Service · el dominio listo
Lo que quedó en el panel: la base de datos, la caché y el correo.

Paso 4: publicar con cada push

El despliegue lo hace GitHub Actions: instala, aplica las migraciones de D1, compila y publica. Push a dev publica el sitio de pruebas; push a main, producción. Tarda unos 2 minutos.

.github/workflows/desplegar.ymlYAML
1- run: pnpm install --frozen-lockfile2- name: Migraciones de D13  run: pnpm exec wrangler d1 migrations apply DB --remote --env "$ENTORNO"4- name: Compilar5  run: pnpm cf:build6- name: Publicar7  run: pnpm exec opennextjs-cloudflare deploy --env "$ENTORNO"
El paso de publicar. El entorno sale de la rama.
Ejecución de GitHub Actions en verde: instalar 19 s, migraciones de D1 2 s, compilar 1 min 19 s y publicar 27 s, en 2 min 14 s en total.
Un despliegue completo: 2 min 14 s.

Paso 5: pruebas y producción

A las 15:20 estaba en vivo pruebas.emanuelconia.com, con contraseña y sin indexar. Ahí probé el flujo con mi correo, revisamos todo el sitio y arreglamos lo que salió. A las 17:21 creé la base de producción, y cerca de las 19:18 emanuelconia.com estaba en vivo. El certificado HTTPS lo emitió Cloudflare solo, en segundos.

Lo que salió mal

  • Una función que en mi máquina sí existía. La forma de cargar los posts daba falso dentro del Worker y tres páginas respondían error 500. Lo encontró la prueba contra el Worker local, no el servidor de desarrollo.
  • Next 15 se quedó sin soporte el mismo día. Next.js da dos años de soporte por versión, y Next 15 los cumplió esa tarde. El adaptador dejó de compilarlo. Migramos a Next 16 antes de producción.
  • El dominio no se dejaba conectar. La vista previa de Cloudflare dijo «sin conflictos», pero al publicar el dominio seguía tomado por dos registros de la página de estacionamiento de Namecheap. Los borré y repetimos solo el paso que falló.
  • El MCP no podía con todo. Leía la documentación y la cuenta, pero no tenía permiso para el DNS ni para activar «Always Use HTTPS». Esos pasos los hice en el panel.
  • La auditoría contaba páginas 404 como correctas. Ahora falla si una página no responde lo que debe.
  • La analítica podía filtrar tokens. Al pasar de un enlace de baja a otra página, la URL completa (con su token) podía llegar a Mixpanel. Ahora se manda sin la consulta.
  • La política de privacidad prometía cosas que el código no hacía. Arreglamos el código, no el texto.

Resultados

Tiempos, tamaños y costos medidos de la migración y el despliegue
QuéResultado
Migración del código43 minutos: 47 archivos, +3.525 / −913 líneas
De decidir a producciónDe las 11:53 a cerca de las 19:18, con auditoría, privacidad y Next 16 en el medio
Despliegue2 min 14 s por push
Worker4,5 MB comprimido
Costo5 USD al mes; 0,00 USD de uso facturable en el período
Uso del período3.370 peticiones, 110 segundos de CPU, 398 filas leídas en D1, 47 MB en R2
  • Inicio de emanuelconia.com: titular «Programar con IA, probado en código real» y el formulario de la lista de testers.emanuelconia.com en vivo
  • Correo «Confirma tu correo» con el botón «Sí, anótame» y el pie con los enlaces de baja y la dirección postal.El correo de confirmación
El sitio en producción y el correo de confirmación que envía Email Service.

Lo que aprendí

  1. Decide la infraestructura antes de publicar. Migrar un sitio sin usuarios costó un día. Con usuarios y datos, habría sido otra historia.
  2. La IA migra rápido; lo lento es lo tuyo. El código tardó 43 minutos. Las cuentas, los pagos, los tokens y el DNS tardaron más, y está bien que sea así.
  3. Pídele que lea la documentación del día. Con el MCP, los precios y límites salen de la fuente, no de lo que el modelo recuerda.
  4. Prueba en el mismo entorno donde vas a publicar. El error 500 no aparecía en el servidor de desarrollo, solo en el Worker.
  5. Publica solo desde CI. Así no viaja nada de tu máquina al sitio.

Hazlo tú: la lista completa

  1. Pasa el DNS de tu dominio a Cloudflare.
  2. Agrega el MCP de Cloudflare a tu agente.
  3. Pide la comparación con documentación vigente (prompt 1) y decide.
  4. Pide la migración en una rama, probada contra el Worker local (prompt 2).
  5. Activa el plan que necesites: Free si es estático, Paid si manda correos o renderiza en el servidor.
  6. Agrega tu dominio a Email Service y deja un solo registro SPF.
  7. Crea la base D1, el bucket R2 y los secretos con wrangler.
  8. Crea un token de API con permisos mínimos y guárdalo en GitHub.
  9. Publica pruebas, prueba con tu correo y revisa todo.
  10. Publica producción. Si el dominio tiene registros viejos, bórralos primero.
wrangler.jsoncjsonc
1{2  "name": "mi-sitio",3  "main": ".open-next/worker.js",4  "compatibility_date": "2026-10-01",5  "compatibility_flags": ["nodejs_compat"],6  "assets": { "directory": ".open-next/assets", "binding": "ASSETS" },7  "triggers": { "crons": ["17 7 * * *"] },8  "env": {9    "produccion": {10      "name": "mi-sitio",11      "routes": [{ "pattern": "midominio.com", "custom_domain": true }],12      "d1_databases": [{ "binding": "DB", "database_name": "mi-sitio", "database_id": "<id>" }],13      "r2_buckets": [{ "binding": "NEXT_INC_CACHE_R2_BUCKET", "bucket_name": "mi-sitio-cache" }],14      "send_email": [{ "name": "EMAIL" }]15    }16  }17}
El esqueleto de un entorno. Los ids salen de wrangler d1 create.

Prueba mis apps antes que nadie

Construyo apps gratis con lo que aprendo. La lista de testers las prueba primero y me dice qué arreglar.

Te escribo para que votes, cuando abra una beta y cuando publique una app. Sin spam.