EmDash는 업로드된 미디어(이미지, 문서, 동영상)를 구성 가능한 스토리지 백엔드에 저장합니다. 배포 플랫폼과 요구 사항에 따라 선택하세요.
개요
| 스토리지 | 적합한 용도 | 특징 |
|---|---|---|
| R2 바인딩 | Cloudflare Workers | 설정 불필요, 빠름 |
| S3 | 모든 플랫폼 | 서명된 업로드, CDN 지원 |
| 로컬 | 개발 | 간단한 파일 시스템 스토리지 |
Cloudflare R2 (바인딩)
Cloudflare Workers에 배포할 때 R2 바인딩을 사용하면 가장 빠르게 통합할 수 있습니다.
import emdash from "emdash/astro";
import { r2 } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
storage: r2({ binding: "MEDIA" }),
}),
],
});
구성
| 옵션 | 타입 | 설명 |
|---|---|---|
binding | string | wrangler.jsonc의 R2 바인딩 이름 |
publicUrl | string | 버킷의 공개 URL (선택 사항) |
설정
Wrangler 구성에 R2 바인딩을 추가합니다:
wrangler.jsonc
{
"r2_buckets": [
{
"binding": "MEDIA",
"bucket_name": "emdash-media"
}
]
} wrangler.toml
[[r2_buckets]]
binding = "MEDIA"
bucket_name = "emdash-media" 공개 접근
미디어 URL을 공개하려면 R2 버킷에서 공개 접근을 활성화하세요:
- Cloudflare 대시보드 > R2 > 해당 버킷
- 설정에서 공개 접근 활성화
- 구성에 공개 URL 추가:
storage: r2({
binding: "MEDIA",
publicUrl: "https://pub-xxxx.r2.dev",
});
S3 호환 스토리지
S3 어댑터는 Cloudflare R2 (S3 API), MinIO 및 기타 S3 호환 서비스에서 작동합니다.
import emdash, { s3 } from "emdash/astro";
export default defineConfig({
integrations: [
emdash({
storage: s3({
endpoint: process.env.S3_ENDPOINT,
bucket: process.env.S3_BUCKET,
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
region: "auto", // Optional, defaults to "auto"
publicUrl: process.env.S3_PUBLIC_URL, // Optional CDN URL
}),
}),
],
});
구성
| 옵션 | 타입 | 필수 | 설명 |
|---|---|---|---|
endpoint | string | 예 | S3 엔드포인트 URL |
bucket | string | 예 | 버킷 이름 |
accessKeyId | string | 아니오* | 액세스 키 |
secretAccessKey | string | 아니오* | 시크릿 키 |
region | string | 아니오 | 리전 (기본값: "auto") |
publicUrl | string | 아니오 | CDN 또는 공개 URL (선택 사항) |
* accessKeyId와 secretAccessKey는 모두 함께 제공하거나 모두 생략해야 합니다.
환경 변수에서 S3 구성 해석
s3({...})에서 생략된 필드는 프로세스 시작 시 대응하는 S3_* 환경 변수에서
읽힙니다. 이를 통해 컨테이너 이미지를 한 번 빌드하고 부팅 시 자격 증명을 주입할 수
있어 재빌드가 필요 없습니다. s3({...})에 명시적으로 지정한 값은 항상 환경 변수보다
우선합니다.
| 환경 변수 | 필드 | 비고 |
|---|---|---|
S3_ENDPOINT | endpoint | 유효한 http/https URL이어야 함 |
S3_BUCKET | bucket | |
S3_ACCESS_KEY_ID | accessKeyId | |
S3_SECRET_ACCESS_KEY | secretAccessKey | |
S3_REGION | region | 기본값 "auto" |
S3_PUBLIC_URL | publicUrl | 선택적 CDN 접두사 |
환경 변수는 프로세스 시작 시 process.env에서 읽힙니다. 이 기능은 Node 전용입니다.
import emdash, { s3 } from "emdash/astro";
export default defineConfig({
integrations: [
emdash({
// s3() with no args: all fields from S3_* environment variables
storage: s3(),
// Or mix: override one field, rest from environment
// storage: s3({ publicUrl: "https://cdn.example.com" }),
}),
],
});
S3 API를 통한 R2
서명된 업로드 URL 등의 기능을 위해 S3 자격 증명으로 R2를 사용합니다:
storage: s3({
endpoint: "https://<account-id>.r2.cloudflarestorage.com",
bucket: "emdash-media",
accessKeyId: process.env.R2_ACCESS_KEY_ID,
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
publicUrl: "https://pub-xxxx.r2.dev",
});
Cloudflare 대시보드의 R2 > Manage R2 API Tokens에서 R2 API 자격 증명을 생성합니다.
MinIO
storage: s3({
endpoint: "https://minio.example.com",
bucket: "emdash-media",
accessKeyId: process.env.MINIO_ACCESS_KEY,
secretAccessKey: process.env.MINIO_SECRET_KEY,
publicUrl: "https://minio.example.com/emdash-media",
});
로컬 파일 시스템
개발에는 로컬 스토리지를 사용합니다. 파일은 디스크의 디렉토리에 저장됩니다.
import emdash, { local } from "emdash/astro";
export default defineConfig({
integrations: [
emdash({
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
}),
}),
],
});
구성
| 옵션 | 타입 | 설명 |
|---|---|---|
directory | string | 파일 저장 디렉토리 |
baseUrl | string | 파일 제공 기본 URL |
사용자 정의 정적 파일 서버를 구성하지 않는 한 baseUrl은 EmDash의 미디어 파일 엔드포인트(/_emdash/api/media/file)와 일치해야 합니다.
환경 기반 구성
환경에 따라 스토리지 백엔드를 전환합니다:
import emdash, { s3, 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 })],
});
서명된 업로드
S3 어댑터는 서명된 업로드 URL을 지원하여 클라이언트가 서버를 거치지 않고 스토리지에 직접 업로드할 수 있습니다. 대용량 파일의 성능이 향상됩니다.
S3 어댑터를 사용하면 서명된 업로드가 자동으로 활성화됩니다. 관리 인터페이스는 지원 시 이를 사용합니다.
서명된 업로드를 지원하는 어댑터:
- S3 (S3 API를 통한 R2 포함)
지원하지 않는 어댑터:
- R2 바인딩 (대신 R2 자격 증명으로 S3 어댑터를 사용)
- 로컬
스토리지 인터페이스
모든 스토리지 어댑터는 동일한 인터페이스를 구현합니다:
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;
}
일관된 인터페이스 덕분에 애플리케이션 코드를 변경하지 않고도 스토리지 백엔드를 전환할 수 있습니다.