Blog do Thiago
← Todos os posts

Blog do Thiago: como construí um CMS completo com Astro 5 e Cloudflare

20 de fevereiro de 2026 8 min de leitura 9
Resumo gerado por IA

Este blog foi construído com Astro 5 no edge da Cloudflare, usando D1 como banco SQLite, Workers AI para geração de conteúdo e MinIO para armazenamento de imagens — tudo com custo zero.

A ideia

Queria um blog pessoal com painel de administração próprio — sem depender do WordPress, Ghost ou qualquer CMS externo. O desafio: rodar tudo no plano gratuito da Cloudflare, sem servidor dedicado.

A solução: Astro 5 no edge da Cloudflare com D1 como banco de dados e Workers AI para funcionalidades de inteligência artificial.

Por que Astro?

O Astro tem uma proposta diferente dos outros frameworks: zero JavaScript por padrão. As páginas do blog são HTML puro geradas no servidor — sem React, sem Vue, sem bundle pesado chegando no browser.

Isso importa muito para SEO e performance. O Lighthouse do blog está consistentemente acima de 95 em todas as métricas.

Islands Architecture

O Astro usa o conceito de Islands — ilhas de interatividade em um oceano de HTML estático. Os formulários, botões de IA e o editor de markdown são "ilhas" que carregam JavaScript só quando necessário.

---
// Código do servidor — roda só no build/request
import { getDb, posts } from '../lib/db';
const allPosts = await getDb(Astro.locals.runtime.env.DB)
  .select().from(posts).all();
---

<!-- HTML puro, zero JS -->
{allPosts.map(post => (
  <article>
    <h2>{post.title}</h2>
  </article>
))}

Stack completa

Framework:    Astro 5 (SSR no edge)
Adapter:      @astrojs/cloudflare v12
Banco:        Cloudflare D1 (SQLite na edge) + Drizzle ORM
Auth:         GitHub OAuth via Arctic v2
IA:           Cloudflare Workers AI (Llama 3 8B)
Storage:      MinIO self-hosted via @aws-sdk/client-s3
Estilo:       Tailwind CSS 4
Deploy:       Cloudflare Pages (gratuito)

Funcionalidades implementadas

Blog público

Painel Admin

Segurança

O acesso ao admin é protegido por GitHub OAuth com allowlist: só o usuário configurado em ADMIN_GITHUB_USERNAME consegue entrar. Qualquer outra conta GitHub recebe 403.

Cloudflare D1: SQLite na edge

O D1 é o banco de dados serverless da Cloudflare — SQLite rodando na mesma edge que processa as requisições. Latência baixíssima, sem cold start de conexão TCP.

Uso o Drizzle ORM para type-safety:

import { drizzle } from 'drizzle-orm/d1';
import * as schema from './schema';

export function getDb(d1: D1Database) {
  return drizzle(d1, { schema });
}

MinIO para imagens

O blog usa meu servidor MinIO self-hosted para armazenar imagens — uma alternativa ao Cloudflare R2 para quem já tem infraestrutura própria.

A integração usa o @aws-sdk/client-s3 com forcePathStyle: true (necessário para MinIO):

const client = new S3Client({
  endpoint: env.MINIO_ENDPOINT,
  credentials: {
    accessKeyId: env.MINIO_ACCESS_KEY,
    secretAccessKey: env.MINIO_SECRET_KEY,
  },
  forcePathStyle: true,
});

Custo total

Serviço Plano Custo
Cloudflare Pages Free R$ 0
Cloudflare D1 Free (5GB, 5M leituras/dia) R$ 0
Cloudflare Workers AI Free (10k neurons/dia) R$ 0
MinIO Self-hosted no meu servidor R$ 0 extra

Total: R$ 0/mês para um blog com IA, upload de imagens e painel admin completo.

Código aberto

O código está disponível no GitHub: github.com/thiago-tap/site_cms

Sinta-se livre para usar como base para o seu próprio blog!

Compartilhar: 𝕏 Twitter/X LinkedIn WhatsApp

Newsletter

Receba novos posts diretamente no seu email.

Posts relacionados

Comentários