Cloudflare Workers fornisce un runtime veloce e distribuito globalmente per EmDash. Questa guida copre la distribuzione con D1 per il database e R2 per l’archiviazione dei media.
Prerequisiti
- Un account Cloudflare
- Wrangler CLI installato (
npm install -g wrangler) - Autenticato con Cloudflare (
wrangler login)
Configurare i Bindings
Crea wrangler.jsonc nella radice del tuo progetto con i bindings D1 e R2. Wrangler fornisce entrambe le risorse al primo deploy se non esistono già.
{
"$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",
},
],
}
Configurare EmDash
Aggiorna la tua configurazione Astro per usare 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" }),
}),
],
});
Primo Avvio
Le migrazioni del database vengono eseguite automaticamente alla prima richiesta dopo il deploy, e ad ogni avvio successivo se c’è qualcosa di nuovo da applicare.
Se il database è vuoto (nessuna collezione) e la procedura guidata di configurazione non è stata completata, EmDash applica anche un file seed al primo avvio. Il seed viene letto al momento della build da .emdash/seed.json, dal percorso in package.json#emdash.seed, o da seed/seed.json — a seconda di quale viene trovato per primo — e incorporato nel bundle. Se nessuno è presente, viene utilizzato un seed predefinito integrato. I deploy successivi contro un database esistente lasciano il suo contenuto invariato.
Distribuire
Distribuisci su Cloudflare Workers:
wrangler deploy
Il tuo sito è ora live su https://my-emdash-site.<your-subdomain>.workers.dev.
Read Replicas
Per siti distribuiti globalmente, abilita la replica in lettura D1 per instradare le query di lettura a repliche vicine invece di colpire sempre il database primario. Questo riduce significativamente la latenza per i visitatori lontani dalla regione primaria.
emdash({
database: d1({
binding: "DB",
session: "auto",
}),
storage: r2({ binding: "MEDIA" }),
}),
Devi anche abilitare la replica in lettura sul database D1 stesso nel dashboard di Cloudflare o tramite l’API REST.
Vedi Opzioni Database — Read Replicas per le modalità di sessione e come funziona la coerenza basata sui segnalibri.
Dominio Personalizzato
Aggiungi un dominio personalizzato nel dashboard di Cloudflare:
- Vai su Workers & Pages > il tuo worker
- Clicca su Custom Domains > Add Custom Domain
- Inserisci il tuo dominio e segui le istruzioni di configurazione DNS
Accesso Pubblico R2
Per servire i media direttamente da R2 (raccomandato per le prestazioni):
- Nel dashboard di Cloudflare, vai su R2 > il tuo bucket
- Clicca su Settings > Public access
- Abilita l’accesso pubblico e annota l’URL pubblico
- Aggiorna la tua configurazione di archiviazione:
storage: r2({
binding: "MEDIA",
publicUrl: "https://pub-xxx.r2.dev"
}),
Autenticazione Cloudflare Access
Se la tua organizzazione utilizza Cloudflare Access, puoi usarlo come provider di autenticazione invece delle passkeys, fornendo single sign-on tramite il tuo provider di identità esistente. La seguente configurazione lo abilita:
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,
},
}),
}),
Vedi la guida all’Autenticazione per le opzioni di configurazione complete.
Variabili d’Ambiente
Raccomandato: chiave di crittografia
EMDASH_ENCRYPTION_KEY è la chiave per crittografare i secret dei plugin a riposo (token webhook, chiavi Turnstile, ecc.). La chiave viene validata all’avvio; la crittografia dei secret dei plugin la utilizza una volta abilitata. Impostala ad ogni deploy in modo che i secret siano protetti senza una successiva modifica della configurazione.
La chiave è fornita da te e non viene mai memorizzata nel database; viene memorizzato solo il testo cifrato crittografato. Perderla significa perdere ogni secret crittografato con essa.
Genera una chiave e memorizzala come secret Worker con i seguenti comandi:
npx emdash secrets generate
wrangler secret put EMDASH_ENCRYPTION_KEY
Opzionale: sovrascritture di valori stabili
EmDash genera automaticamente il secret HMAC di anteprima e il salt hash IP dei commentatori e li persiste nel database al primo utilizzo. Le variabili d’ambiente sottostanti sono sovrascritture per i casi in cui devi fissare il valore tu stesso — ad esempio, quando un Worker di anteprima in un processo separato deve condividere il secret con il tuo sito principale.
| Variabile | Scopo |
|---|---|
EMDASH_PREVIEW_SECRET | Sovrascrittura per il secret HMAC di anteprima generato automaticamente. |
EMDASH_IP_SALT | Sovrascrittura per il salt hash IP dei commentatori generato automaticamente. |
EMDASH_AUTH_SECRET | Opzionale. Se impostato, viene utilizzato come fonte di salt IP (a meno che non sia impostato anche EMDASH_IP_SALT, che ha la precedenza), mantenendo stabili gli hash IP dei commentatori per le installazioni che già ne dipendono. Lascialo non impostato per un nuovo deploy. |
Accedi alle variabili d’ambiente nella tua configurazione usando import.meta.env o il binding env di Cloudflare.
Deploy di Anteprima
Distribuisci un branch di anteprima:
wrangler deploy --env preview
Aggiungi una sezione di ambiente a wrangler.jsonc:
{
"env": {
"preview": {
"d1_databases": [
{
"binding": "DB",
"database_name": "emdash-db-preview",
},
],
},
},
}
Risoluzione dei Problemi
”D1 binding not found”
Verifica che il nome del binding in wrangler.jsonc corrisponda alla tua configurazione del database:
// Must match: d1({ binding: "DB" })
"binding": "DB"
“R2 binding not found”
Verifica che il bucket R2 sia correttamente collegato:
// Must match: r2({ binding: "MEDIA" })
"binding": "MEDIA"
Errori di migrazione
Se vedi errori di schema, segui i log del Worker (wrangler tail) e riproduci l’errore per catturare il messaggio sottostante — quindi apri un issue con quell’output.