Implantar no Cloudflare

Nesta página

Cloudflare Workers fornece um runtime rápido e distribuído globalmente para EmDash. Este guia cobre a implantação com D1 para o banco de dados e R2 para armazenamento de mídia.

Pré-requisitos

  • Uma conta Cloudflare
  • Wrangler CLI instalado (npm install -g wrangler)
  • Autenticado com Cloudflare (wrangler login)

Configurar Bindings

Crie wrangler.jsonc na raiz do seu projeto com bindings D1 e R2. O Wrangler provisiona ambos os recursos na primeira implantação se ainda não existirem.

{
	"$schema": "node_modules/wrangler/config-schema.json",
	"name": "my-emdash-site",
	"compatibility_date": "2025-01-15",
	"compatibility_flags": ["nodejs_compat"],

	"d1_databases": [
		{
			"binding": "DB",
			"database_name": "emdash-db",
		},
	],

	"r2_buckets": [
		{
			"binding": "MEDIA",
			"bucket_name": "emdash-media",
		},
	],
}

Configurar EmDash

Atualize sua configuração Astro para usar D1 e R2:

import { defineConfig } from "astro/config";
import cloudflare from "@astrojs/cloudflare";
import emdash from "emdash/astro";
import { d1, r2 } from "@emdash-cms/cloudflare";

export default defineConfig({
	output: "server",
	adapter: cloudflare(),
	integrations: [
		emdash({
			database: d1({ binding: "DB" }),
			storage: r2({ binding: "MEDIA" }),
		}),
	],
});

Primeira Inicialização

As migrações do banco de dados são executadas automaticamente na primeira solicitação após a implantação, e em cada inicialização subsequente se houver algo novo para aplicar.

Se o banco de dados estiver vazio (sem coleções) e o assistente de configuração não tiver sido concluído, EmDash também aplica um arquivo seed na primeira inicialização. O seed é lido no momento da compilação de .emdash/seed.json, do caminho em package.json#emdash.seed, ou de seed/seed.json — o que for encontrado primeiro — e incorporado ao bundle. Se nenhum estiver presente, um seed padrão integrado é usado. Implantações subsequentes contra um banco de dados existente deixam seu conteúdo intocado.

Implantar

Implante no Cloudflare Workers:

wrangler deploy

Seu site está agora ativo em https://my-emdash-site.<your-subdomain>.workers.dev.

Read Replicas

Para sites distribuídos globalmente, habilite a replicação de leitura D1 para rotear consultas de leitura para réplicas próximas em vez de sempre acessar o banco de dados primário. Isso reduz significativamente a latência para visitantes distantes da região primária.

emdash({
	database: d1({
		binding: "DB",
		session: "auto",
	}),
	storage: r2({ binding: "MEDIA" }),
}),

Você também precisa habilitar a replicação de leitura no próprio banco de dados D1 no painel do Cloudflare ou via API REST.

Consulte Opções de Banco de Dados — Read Replicas para modos de sessão e como funciona a consistência baseada em marcadores.

Domínio Personalizado

Adicione um domínio personalizado no painel do Cloudflare:

  1. Vá para Workers & Pages > seu worker
  2. Clique em Custom Domains > Add Custom Domain
  3. Digite seu domínio e siga as instruções de configuração DNS

Acesso Público R2

Para servir mídia diretamente do R2 (recomendado para desempenho):

  1. No painel do Cloudflare, vá para R2 > seu bucket
  2. Clique em Settings > Public access
  3. Habilite o acesso público e anote a URL pública
  4. Atualize sua configuração de armazenamento:
storage: r2({
  binding: "MEDIA",
  publicUrl: "https://pub-xxx.r2.dev"
}),

Autenticação Cloudflare Access

Se sua organização usa Cloudflare Access, você pode usá-lo como provedor de autenticação em vez de passkeys, fornecendo login único através do seu provedor de identidade existente. A seguinte configuração o habilita:

emdash({
  database: d1({ binding: "DB" }),
  storage: r2({ binding: "MEDIA" }),
  auth: access({
    teamDomain: "myteam.cloudflareaccess.com",
    audience: "your-app-audience-tag",
    roleMapping: {
      "Admins": 50,
      "Editors": 40,
    },
  }),
}),

Consulte o guia de Autenticação para opções de configuração completas.

Variáveis de Ambiente

Recomendado: chave de criptografia

EMDASH_ENCRYPTION_KEY é a chave para criptografar segredos de plugins em repouso (tokens de webhook, chaves Turnstile, etc.). A chave é validada na inicialização; a criptografia de segredos de plugins a usa uma vez habilitada. Defina-a em cada implantação para que os segredos sejam protegidos sem uma mudança de configuração posterior.

A chave é fornecida por você e nunca armazenada no banco de dados; apenas o texto cifrado criptografado é armazenado. Perdê-la significa perder cada segredo criptografado com ela.

Gere uma chave e armazene-a como um segredo Worker com os seguintes comandos:

npx emdash secrets generate
wrangler secret put EMDASH_ENCRYPTION_KEY

Opcional: substituições de valores estáveis

EmDash gera automaticamente o segredo HMAC de visualização e o salt de hash de IP do comentarista e os persiste no banco de dados no primeiro uso. As variáveis de ambiente abaixo são substituições para casos em que você precisa fixar o valor você mesmo — por exemplo, quando um Worker de visualização em um processo separado precisa compartilhar o segredo com seu site principal.

VariávelPropósito
EMDASH_PREVIEW_SECRETSubstituição para o segredo HMAC de visualização gerado automaticamente.
EMDASH_IP_SALTSubstituição para o salt de hash de IP do comentarista gerado automaticamente.
EMDASH_AUTH_SECRETOpcional. Se definido, é usado como fonte de salt de IP (a menos que EMDASH_IP_SALT também esteja definido, que tem precedência), mantendo hashes de IP do comentarista estáveis para instalações que já dependem dele. Deixe-o indefinido para uma nova implantação.

Acesse variáveis de ambiente na sua configuração usando import.meta.env ou o binding env do Cloudflare.

Implantações de Visualização

Implante um branch de visualização:

wrangler deploy --env preview

Adicione uma seção de ambiente ao wrangler.jsonc:

{
	"env": {
		"preview": {
			"d1_databases": [
				{
					"binding": "DB",
					"database_name": "emdash-db-preview",
				},
			],
		},
	},
}

Solução de Problemas

”D1 binding not found”

Verifique se o nome do binding em wrangler.jsonc corresponde à sua configuração de banco de dados:

// Must match: d1({ binding: "DB" })
"binding": "DB"

“R2 binding not found”

Verifique se o bucket R2 está corretamente vinculado:

// Must match: r2({ binding: "MEDIA" })
"binding": "MEDIA"

Erros de migração

Se você vir erros de esquema, rastreie os logs do Worker (wrangler tail) e reproduza o erro para capturar a mensagem subjacente — então abra uma issue com essa saída.