Scegli un adattatore di storage per i media caricati. Un backup del database contiene i metadati dei media, non i file archiviati, quindi fai il backup del backend di storage separatamente.
Panoramica
| Storage | Usalo quando | Upload firmati |
|---|---|---|
| R2 binding | Il sito gira su Cloudflare Workers | No |
| S3 | Un sito Node.js usa AWS S3, l’API S3 di R2, MinIO o storage compatibile | Sì |
| Locale | Un sito Node.js ha un volume persistente scrivibile | No |
Cloudflare R2 binding
Usa l’adattatore di binding R2 su Cloudflare Workers. Il binding fornisce l’accesso a runtime, quindi il sito non necessita di chiavi di accesso R2.
import emdash from "emdash/astro";
import { r2 } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
storage: r2({ binding: "MEDIA" }),
}),
],
});
Configurazione
| Opzione | Tipo | Descrizione |
|---|---|---|
binding | string | Nome del binding R2 da wrangler.jsonc |
publicUrl | string | URL pubblica opzionale per il bucket |
Setup
Aggiungi il binding R2 alla tua configurazione Wrangler:
wrangler.jsonc
{
"r2_buckets": [
{
"binding": "MEDIA",
"bucket_name": "emdash-media"
}
]
} wrangler.toml
[[r2_buckets]]
binding = "MEDIA"
bucket_name = "emdash-media" Accesso pubblico
Per servire media da un bucket pubblico, connetti un dominio personalizzato con l’API Cloudflare, poi imposta la sua origine come publicUrl. L’URL di sviluppo r2.dev di Cloudflare ha limiti di velocità e non è pensata per il traffico di produzione.
storage: r2({
binding: "MEDIA",
publicUrl: "https://media.example.com",
});
Se lo stesso bucket archivia backup JSON automatici, un’origine di bucket pubblico può esporre oggetti sotto backups/. Usa un bucket privato e la route media di EmDash, o limita l’origine pubblica agli oggetti media. Vedi Backup.
Storage compatibile S3
L’adattatore S3 funziona su Node.js con l’API S3 di Cloudflare R2, AWS S3, MinIO e servizi compatibili.
La seguente configurazione risolve endpoint, bucket, credenziali, regione e URL pubblica opzionale dalle variabili S3_* all’avvio del processo Node.js:
import emdash, { s3 } from "emdash/astro";
export default defineConfig({
integrations: [
emdash({
storage: s3(),
}),
],
});
Configurazione
| Opzione | Tipo | Richiesto | Descrizione |
|---|---|---|---|
endpoint | string | sì | URL endpoint S3 |
bucket | string | sì | Nome del bucket |
accessKeyId | string | no* | Chiave di accesso |
secretAccessKey | string | no* | Chiave segreta |
region | string | no | Regione (default: "auto") |
publicUrl | string | no | CDN o URL pubblica opzionale |
* Sia accessKeyId che secretAccessKey devono essere forniti insieme, o entrambi omessi.
Risolvere la config S3 dalle variabili d’ambiente
Ogni campo omesso da s3({...}) viene letto dalla variabile d’ambiente S3_* corrispondente all’avvio del processo. Questo permette di costruire un’immagine container una volta e iniettare le credenziali all’avvio senza ricostruire. I valori espliciti in s3({...}) hanno sempre la precedenza sulle variabili d’ambiente.
| Variabile d’ambiente | Campo | Note |
|---|---|---|
S3_ENDPOINT | endpoint | Deve essere un URL http/https valido |
S3_BUCKET | bucket | |
S3_ACCESS_KEY_ID | accessKeyId | |
S3_SECRET_ACCESS_KEY | secretAccessKey | |
S3_REGION | region | Default: "auto" |
S3_PUBLIC_URL | publicUrl | Prefisso CDN opzionale |
Le variabili d’ambiente vengono lette da process.env all’avvio del processo. Questa è una funzionalità solo Node.
Chiamare s3() senza argomenti legge ogni campo dalle variabili d’ambiente S3_*:
import emdash, { s3 } from "emdash/astro";
export default defineConfig({
integrations: [
emdash({
// s3() senza argomenti: tutti i campi dalle variabili S3_*
storage: s3(),
// O mischiare: sovrascrivere un campo, il resto dall'ambiente
// storage: s3({ publicUrl: "https://cdn.example.com" }),
}),
],
});
R2 via API S3
Usa l’adattatore S3 su Node.js quando sono richiesti upload firmati diretti a R2. Crea credenziali API R2 con ambito limitato con l’API o CLI Cloudflare, poi imposta le seguenti variabili runtime:
S3_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com
S3_BUCKET=emdash-media
S3_ACCESS_KEY_ID=<r2-access-key-id>
S3_SECRET_ACCESS_KEY=<r2-secret-access-key>
S3_REGION=auto
S3_PUBLIC_URL=https://media.example.com
Conserva i valori reali nel gestore dei segreti della piattaforma di hosting Node.js. L’URL pubblica è opzionale e non sostituisce l’endpoint dell’API S3 usato per gli upload.
MinIO
Punta le stesse variabili runtime a MinIO. Imposta S3_ENDPOINT all’origine dell’API MinIO, S3_BUCKET al nome del bucket, e le due variabili di credenziali a una chiave di accesso MinIO con ambito limitato. Imposta S3_PUBLIC_URL solo quando quell’origine serve gli oggetti del bucket pubblicamente.
Sistema di file locale
Usa lo storage locale per lo sviluppo o un singolo server Node.js con disco persistente. I file sono archiviati in una directory su quel disco.
import emdash, { local } from "emdash/astro";
export default defineConfig({
integrations: [
emdash({
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
}),
}),
],
});
Configurazione
| Opzione | Tipo | Descrizione |
|---|---|---|
directory | string | Percorso directory per lo storage |
baseUrl | string | URL base per servire i file |
La baseUrl dovrebbe corrispondere all’endpoint file media di EmDash (/_emdash/api/media/file) a meno che non configuri un server di file statici personalizzato.
Usare storage separati per ambienti separati
La seguente configurazione usa una directory locale durante lo sviluppo e R2 nel build di produzione Cloudflare:
import emdash, { local } from "emdash/astro";
import { r2 } from "@emdash-cms/cloudflare";
const storage = import.meta.env.PROD
? r2({ binding: "MEDIA" })
: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
});
export default defineConfig({
integrations: [emdash({ storage })],
});
Upload firmati
L’adattatore S3 supporta URL di upload firmati, permettendo ai client di caricare direttamente nello storage senza passare dal server. Questo migliora le prestazioni per file grandi.
Gli upload firmati sono automatici usando l’adattatore S3. L’interfaccia admin li usa quando disponibili.
Adattatori che supportano upload firmati:
- S3 (incluso R2 via API S3)
Adattatori che non supportano upload firmati:
- R2 binding (usa l’adattatore S3 con credenziali R2 invece)
- Locale
Interfaccia di storage
Tutti gli adattatori di storage implementano la stessa interfaccia:
interface Storage {
upload(options: {
key: string;
body: Buffer | Uint8Array | ReadableStream;
contentType: string;
}): Promise<UploadResult>;
download(key: string): Promise<DownloadResult>;
delete(key: string): Promise<void>;
exists(key: string): Promise<boolean>;
list(options?: ListOptions): Promise<ListResult>;
getSignedUploadUrl(options: SignedUploadOptions): Promise<SignedUploadUrl>;
getPublicUrl(key: string): string;
}
Questa coerenza permette di cambiare backend di storage senza modificare il codice dell’applicazione.