Escolher armazenamento de mídia

Nesta página

Escolha um adaptador de armazenamento para mídia carregada. Um backup de banco de dados contém metadados de mídia, não os arquivos armazenados, então faça backup do backend de armazenamento separadamente.

Visão geral

ArmazenamentoQuando usarUpload assinado
R2 bindingO site roda no Cloudflare WorkersNão
S3Um site Node.js usa AWS S3, API S3 do R2, MinIO ou armazenamento compatívelSim
LocalUm site Node.js tem um volume persistente gravávelNão

Cloudflare R2 binding

Use o adaptador de binding R2 no Cloudflare Workers. O binding fornece acesso em tempo de execução, então o site não precisa de chaves de acesso R2.

import emdash from "emdash/astro";
import { r2 } from "@emdash-cms/cloudflare";

export default defineConfig({
	integrations: [
		emdash({
			storage: r2({ binding: "MEDIA" }),
		}),
	],
});

Configuração

OpçãoTipoDescrição
bindingstringNome do binding R2 do wrangler.jsonc
publicUrlstringURL pública opcional para o bucket

Setup

Adicione o binding R2 à sua configuração Wrangler:

wrangler.jsonc

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

wrangler.toml

[[r2_buckets]]
binding = "MEDIA"
bucket_name = "emdash-media"

Acesso público

Para servir mídia de um bucket público, conecte um domínio personalizado com a API Cloudflare, depois defina sua origem como publicUrl. A URL de desenvolvimento r2.dev do Cloudflare tem limites de taxa e não é destinada para tráfego de produção.

storage: r2({
	binding: "MEDIA",
	publicUrl: "https://media.example.com",
});

Se o mesmo bucket armazena backups JSON automáticos, uma origem de bucket público pode expor objetos sob backups/. Use um bucket privado e a rota de mídia do EmDash, ou restrinja a origem pública a objetos de mídia. Veja Backups.

Armazenamento compatível com S3

O adaptador S3 funciona no Node.js com a API S3 do Cloudflare R2, AWS S3, MinIO e serviços compatíveis.

A seguinte configuração resolve endpoint, bucket, credenciais, região e URL pública opcional das variáveis S3_* na inicialização do processo Node.js:

import emdash, { s3 } from "emdash/astro";

export default defineConfig({
	integrations: [
		emdash({
			storage: s3(),
		}),
	],
});

Configuração

OpçãoTipoObrigatórioDescrição
endpointstringsimURL do endpoint S3
bucketstringsimNome do bucket
accessKeyIdstringnão*Chave de acesso
secretAccessKeystringnão*Chave secreta
regionstringnãoRegião (padrão: "auto")
publicUrlstringnãoCDN opcional ou URL pública

* Tanto accessKeyId quanto secretAccessKey devem ser fornecidos juntos, ou ambos omitidos.

Resolver config S3 de variáveis de ambiente

Todo campo omitido de s3({...}) é lido da variável de ambiente S3_* correspondente na inicialização do processo. Isso permite construir uma imagem de container uma vez e injetar credenciais na inicialização sem reconstruir. Valores explícitos em s3({...}) sempre têm precedência sobre variáveis de ambiente.

Variável de ambienteCampoNotas
S3_ENDPOINTendpointDeve ser uma URL http/https válida
S3_BUCKETbucket
S3_ACCESS_KEY_IDaccessKeyId
S3_SECRET_ACCESS_KEYsecretAccessKey
S3_REGIONregionPadrão "auto"
S3_PUBLIC_URLpublicUrlPrefixo CDN opcional

As variáveis de ambiente são lidas de process.env na inicialização do processo. Esta é uma funcionalidade apenas do Node.

Chamar s3() sem argumentos lê todos os campos das variáveis de ambiente S3_*:

import emdash, { s3 } from "emdash/astro";

export default defineConfig({
	integrations: [
		emdash({
			// s3() sem argumentos: todos os campos das variáveis S3_*
			storage: s3(),

			// Ou misto: sobrescrever um campo, resto do ambiente
			// storage: s3({ publicUrl: "https://cdn.example.com" }),
		}),
	],
});

R2 via API S3

Use o adaptador S3 no Node.js quando uploads assinados diretos para R2 são necessários. Crie credenciais de API R2 com escopo limitado com a API ou CLI Cloudflare, depois defina as seguintes variáveis de 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

Mantenha os valores reais no gerenciador de secrets da plataforma de hospedagem Node.js. A URL pública é opcional e não substitui o endpoint da API S3 usado para uploads.

MinIO

Aponte as mesmas variáveis de runtime para o MinIO. Defina S3_ENDPOINT como a origem da API MinIO, S3_BUCKET como o nome do bucket, e as duas variáveis de credenciais como uma chave de acesso MinIO com escopo limitado. Defina S3_PUBLIC_URL apenas quando essa origem serve objetos do bucket publicamente.

Sistema de arquivos local

Use armazenamento local para desenvolvimento ou um único servidor Node.js com disco persistente. Os arquivos são armazenados em um diretório nesse disco.

import emdash, { local } from "emdash/astro";

export default defineConfig({
	integrations: [
		emdash({
			storage: local({
				directory: "./uploads",
				baseUrl: "/_emdash/api/media/file",
			}),
		}),
	],
});

Configuração

OpçãoTipoDescrição
directorystringCaminho do diretório de armazenamento
baseUrlstringURL base para servir arquivos

O baseUrl deve corresponder ao endpoint de arquivo de mídia do EmDash (/_emdash/api/media/file) a menos que você configure um servidor de arquivos estáticos personalizado.

Usar armazenamentos separados para ambientes separados

A seguinte configuração usa um diretório local durante o desenvolvimento e R2 no build de produção 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 })],
});

Uploads assinados

O adaptador S3 suporta URLs de upload assinados, permitindo que clientes façam upload diretamente para o armazenamento sem passar pelo servidor. Isso melhora o desempenho para arquivos grandes.

Uploads assinados são automáticos usando o adaptador S3. A interface admin os usa quando disponíveis.

Adaptadores que suportam uploads assinados:

  • S3 (incluindo R2 via API S3)

Adaptadores que não suportam uploads assinados:

  • R2 binding (use o adaptador S3 com credenciais R2 em vez disso)
  • Local

Interface de armazenamento

Todos os adaptadores de armazenamento implementam a mesma interface:

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;
}

Essa consistência permite trocar backends de armazenamento sem alterar o código da aplicação.