업로드된 미디어용 스토리지 어댑터를 하나 선택하세요. 데이터베이스 백업에는 미디어 메타데이터만 포함되고 저장된 파일은 포함되지 않으므로, 스토리지 백엔드는 별도로 백업하세요.
개요
| 스토리지 | 사용 시기 | 서명된 업로드 |
|---|---|---|
| R2 바인딩 | 사이트가 Cloudflare Workers에서 실행될 때 | 아니오 |
| S3 | Node.js 사이트가 AWS S3, R2의 S3 API, MinIO 또는 호환 스토리지를 사용할 때 | 예 |
| 로컬 | Node.js 사이트에 쓰기 가능한 영구 볼륨이 있을 때 | 아니오 |
Cloudflare R2 바인딩
Cloudflare Workers에서 R2 바인딩 어댑터를 사용합니다. 바인딩이 런타임에 접근을 제공하므로, 사이트는 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" 공개 접근
공개 버킷에서 미디어를 제공하려면 Cloudflare API로 커스텀 도메인을 연결한 다음 해당 오리진을 publicUrl로 설정합니다. Cloudflare의 r2.dev 개발 URL은 레이트 리밋이 있으며 프로덕션 트래픽용이 아닙니다.
storage: r2({
binding: "MEDIA",
publicUrl: "https://media.example.com",
});
같은 버킷이 자동 JSON 백업을 저장하는 경우, 공개 버킷 오리진이 backups/ 아래의 객체를 노출할 수 있습니다. 프라이빗 버킷과 EmDash의 미디어 라우트를 사용하거나, 공개 오리진을 미디어 객체로 제한하세요. 백업을 참조하세요.
S3 호환 스토리지
S3 어댑터는 Node.js에서 Cloudflare R2의 S3 API, AWS S3, MinIO 및 호환 서비스와 작동합니다.
다음 구성은 Node.js 프로세스 시작 시 S3_* 변수에서 엔드포인트, 버킷, 자격 증명, 리전 및 선택적 공개 URL을 해석합니다:
import emdash, { s3 } from "emdash/astro";
export default defineConfig({
integrations: [
emdash({
storage: s3(),
}),
],
});
구성
| 옵션 | 타입 | 필수 | 설명 |
|---|---|---|---|
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 전용 기능입니다.
인수 없이 s3()를 호출하면 S3_* 환경 변수에서 모든 필드를 읽습니다:
import emdash, { s3 } from "emdash/astro";
export default defineConfig({
integrations: [
emdash({
// 인수 없는 s3(): 모든 필드를 S3_* 환경 변수에서
storage: s3(),
// 또는 혼합: 하나의 필드를 오버라이드, 나머지는 환경에서
// storage: s3({ publicUrl: "https://cdn.example.com" }),
}),
],
});
S3 API를 통한 R2
R2로의 직접 서명된 업로드가 필요할 때 Node.js에서 S3 어댑터를 사용합니다. Cloudflare API 또는 CLI로 범위가 제한된 R2 API 자격 증명을 만든 후 다음 런타임 변수를 설정하세요:
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
실제 값은 Node.js 호스팅 플랫폼의 시크릿 매니저에 보관하세요. 공개 URL은 선택사항이며 업로드에 사용되는 S3 API 엔드포인트를 대체하지 않습니다.
MinIO
같은 런타임 변수를 MinIO로 지정합니다. S3_ENDPOINT를 MinIO API 오리진으로, S3_BUCKET을 버킷 이름으로, 두 자격 증명 변수를 범위가 제한된 MinIO 액세스 키로 설정합니다. 해당 오리진이 버킷의 객체를 공개적으로 제공하는 경우에만 S3_PUBLIC_URL을 설정하세요.
로컬 파일 시스템
개발 또는 영구 디스크가 있는 단일 Node.js 서버에 로컬 스토리지를 사용합니다. 파일은 해당 디스크의 디렉토리에 저장됩니다.
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)와 일치해야 합니다.
환경별로 다른 스토리지 사용
다음 구성은 개발 중에 로컬 디렉토리를 사용하고 Cloudflare 프로덕션 빌드에서 R2를 사용합니다:
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 })],
});
서명된 업로드
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;
}
이 일관성으로 애플리케이션 코드를 변경하지 않고 스토리지 백엔드를 전환할 수 있습니다.