Cloudflare R2
O caminho de produção pro armazenamento de anexos — egress livre, que é do que servir imagem de chat pra uma comunidade de verdade precisa.
O storage compatível com S3 da Cloudflare. Escolha este pra produção: o egress é livre, então servir as imagens de volta pra sua comunidade não custa nada além do armazenamento.
A Cloudflare pede cartão
O R2 exige método de pagamento pra habilitar, mesmo no plano gratuito. Dentro da cota grátis (10 GB de armazenamento) a cobrança é US$ 0. Se você quer evitar o cartão por completo, use o Neon Object Storage.
Todo passo aqui acontece no navegador — não existe CLI pra este caminho.
Abra o dashboard da Cloudflare e faça login. No menu do lado esquerdo da tela, clique em Storage & Databases e, dentro dele, em R2 Object Storage.
Na primeira vez que você abre o R2, a Cloudflare pede pra ativar o serviço e pra cadastrar um método de pagamento.
Clique em Create bucket. Digite um nome (ex: opencall-uploads), deixe a
localização em Automatic e confirme.

O nome vira o R2_BUCKET.
Clique em Manage API Tokens — o que fica dentro do painel do R2, não a página de API Tokens da conta — e depois em Create API Token.
Dê permissão Object Read & Write e restrinja ao bucket do passo 2.

Isso gera R2_ACCESS_KEY_ID e R2_SECRET_ACCESS_KEY. Os dois aparecem uma
única vez — copie agora.
Copie o Account ID que aparece na lateral direita de qualquer página do
dashboard da Cloudflare → R2_ACCOUNT_ID.
Volte ao bucket → Settings → Public Access. Habilite a URL pública
padrão (formato pub-xxxxxxxx.r2.dev), ou conecte um domínio seu.

Essa URL, com https:// na frente e sem barra no fim, vira o
NEXT_PUBLIC_R2_PUBLIC_BASE_URL.
Sem acesso público, nenhuma imagem carrega
Nem pra quem já está logado. O bucket guarda só imagens que os usuários anexaram no chat, então leitura pública é a configuração esperada aqui, não um erro.
Variáveis desta etapa
| Variável | Valor |
|---|---|
R2_BUCKET | Nome do bucket (opencall-uploads) |
R2_ACCOUNT_ID | Account ID da Cloudflare |
R2_ACCESS_KEY_ID | Do API Token |
R2_SECRET_ACCESS_KEY | Do API Token |
NEXT_PUBLIC_R2_PUBLIC_BASE_URL | URL pública do bucket |
O R2_ENDPOINT e o R2_REGION ficam vazios neste caminho: o app deriva o
endpoint do R2_ACCOUNT_ID, e o R2 exige a região auto, que é o padrão.