Cloudflare Workers는 EmDash를 위한 빠르고 전 세계에 분산된 런타임을 제공합니다. 이 가이드는 데이터베이스로 D1, 미디어 저장소로 R2를 사용하는 배포를 다룹니다.
사전 요구 사항
- Cloudflare 계정
- Wrangler CLI 설치(
npm install -g wrangler) - Cloudflare 로그인 완료(
wrangler login)
리소스 만들기
1. D1 데이터베이스 생성
wrangler d1 create emdash-db
출력에서 database_id를 기록합니다.
2. R2 버킷 생성
wrangler r2 bucket create emdash-media
3. wrangler.jsonc 생성
프로젝트 루트에 wrangler.jsonc를 만듭니다.
{
"$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",
"database_id": "your-database-id",
},
],
"r2_buckets": [
{
"binding": "MEDIA",
"bucket_name": "emdash-media",
},
],
}
EmDash 구성
Astro 설정을 D1과 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" }),
}),
],
});
마이그레이션 실행
데이터베이스 스키마를 생성하고 적용합니다.
1. 스키마 SQL보내기
npx emdash init --database ./data.db
2. D1에 마이그레이션 적용
wrangler d1 migrations apply emdash-db
마이그레이션 파일이 없으면 코어 스키마를 직접 적용합니다.
wrangler d1 execute emdash-db --file=./node_modules/emdash/migrations/0001_core.sql
배포
Cloudflare Workers에 배포합니다.
wrangler deploy
사이트는 https://my-emdash-site.<your-subdomain>.workers.dev에서 제공됩니다.
읽기 복제본
전 세계에 분산된 사이트의 경우 D1 읽기 복제를 켜면 읽기 쿼리가 항상 기본 데이터베이스가 아니라 가까운 복제본으로 라우팅됩니다. 기본 리전에서 먼 방문자의 지연 시간이 크게 줄어듭니다.
emdash({
database: d1({
binding: "DB",
session: "auto",
}),
storage: r2({ binding: "MEDIA" }),
}),
D1 데이터베이스 자체에 대해서도 Cloudflare 대시보드 또는 REST API에서 읽기 복제를 활성화해야 합니다.
세션 모드와 북마크 기반 일관성은 데이터베이스 옵션 — 읽기 복제본을 참조하세요.
사용자 지정 도메인
Cloudflare 대시보드에서 사용자 지정 도메인을 추가합니다.
- Workers & Pages > 해당 Worker
- Custom Domains > Add Custom Domain
- 도메인을 입력하고 DNS 안내를 따릅니다
R2 공개 액세스
미디어를 R2에서 직접 제공하려면(성능상 권장):
- Cloudflare 대시보드에서 R2 > 해당 버킷
- Settings > Public access
- 공개 액세스를 켜고 공개 URL을 기록
- 스토리지 설정 업데이트:
storage: r2({
binding: "MEDIA",
publicUrl: "https://pub-xxx.r2.dev"
}),
Cloudflare Access 인증
조직에서 Cloudflare Access를 사용하는 경우 패스키 대신 인증 공급자로 사용할 수 있습니다. 기존 IdP와 SSO를 제공합니다.
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,
},
}),
}),
전체 구성 옵션은 인증 가이드를 참조하세요.
환경 변수
EmDash는 인증과 미리보기 기능에 특정 시크릿이 필요합니다.
필수 시크릿
| 변수 | 용도 |
|---|---|
EMDASH_AUTH_SECRET | 세션 쿠키와 인증 토큰 서명. 프로덕션에 필수. |
EMDASH_PREVIEW_SECRET | 초안 미리보기 URL 서명. 미리보기에 필수. |
안전한 시크릿 생성:
npx emdash auth secret
Wrangler로 시크릿 설정:
wrangler secret put EMDASH_AUTH_SECRET
wrangler secret put EMDASH_PREVIEW_SECRET
설정에서는 import.meta.env 또는 Cloudflare env 바인딩으로 환경 변수에 액세스합니다.
프리뷰 배포
프리뷰 브랜치 배포:
wrangler deploy --env preview
wrangler.jsonc에 환경 섹션 추가:
{
"env": {
"preview": {
"d1_databases": [
{
"binding": "DB",
"database_name": "emdash-db-preview",
"database_id": "your-preview-db-id",
},
],
},
},
}
문제 해결
”D1 binding not found”
wrangler.jsonc의 바인딩 이름이 데이터베이스 구성과 일치하는지 확인하세요.
// 일치해야 함: d1({ binding: "DB" })
"binding": "DB"
”R2 binding not found”
R2 버킷이 올바르게 바인딩되었는지 확인하세요.
// 일치해야 함: r2({ binding: "MEDIA" })
"binding": "MEDIA"
마이그레이션 오류
D1 마이그레이션은 런타임이 아니라 Wrangler로 실행됩니다. 스키마 오류가 있으면:
- 마이그레이션 적용 여부 확인:
wrangler d1 migrations list emdash-db - 필요 시 다시 적용:
wrangler d1 migrations apply emdash-db