구성 참조

이 페이지

EmDash는 통합용 astro.config.mjs와 콘텐츠 컬렉션용 src/live.config.ts라는 두 파일을 통해 구성됩니다.

Astro 통합

EmDash를 Astro 통합으로 구성합니다:

import { defineConfig } from "astro/config";
import emdash, { local, r2, s3 } from "emdash/astro";
import { sqlite, libsql, d1 } from "emdash/db";

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

통합 옵션

database

필수. 데이터베이스 어댑터 구성입니다.

// SQLite (Node.js)
database: sqlite({ url: "file:./data.db" });

// PostgreSQL
database: postgres({ connectionString: process.env.DATABASE_URL });

// libSQL
database: libsql({
	url: process.env.LIBSQL_DATABASE_URL,
	authToken: process.env.LIBSQL_AUTH_TOKEN,
});

// Cloudflare D1 (@emdash-cms/cloudflare에서 가져오기)
database: d1({ binding: "DB" });

자세한 내용은 데이터베이스 옵션을 참조하세요.

storage

필수. 미디어 스토리지 어댑터 구성입니다.

// 로컬 파일 시스템(개발용)
storage: local({
	directory: "./uploads",
	baseUrl: "/_emdash/api/media/file",
});

// R2 바인딩(Cloudflare Workers)
storage: r2({
	binding: "MEDIA",
	publicUrl: "https://pub-xxxx.r2.dev", // optional
});

// S3-compatible (any platform) — all fields from S3_* environment variables
storage: s3()

// Or with explicit values
storage: s3({
	endpoint: "https://s3.amazonaws.com",
	bucket: "my-bucket",
	accessKeyId: process.env.S3_ACCESS_KEY_ID,
	secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
	region: "us-east-1", // optional, default: "auto"
	publicUrl: "https://cdn.example.com", // optional
});

자세한 내용은 스토리지 옵션을 참조하세요.

plugins

선택 사항. EmDash 플러그인 배열.

import seoPlugin from "@emdash-cms/plugin-seo";

plugins: [seoPlugin()];

auth

선택 사항. 인증 구성.

auth: {
  // 자체 가입 구성
  selfSignup: {
    domains: ["example.com"],
    defaultRole: 20, // Contributor
  },
  
  // OAuth 공급자
  oauth: {
    github: {
      clientId: process.env.GITHUB_CLIENT_ID,
      clientSecret: process.env.GITHUB_CLIENT_SECRET,
    },
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    },
  },
  
  // 세션 구성
  session: {
    maxAge: 30 * 24 * 60 * 60, // 30일
    sliding: true, // 활동 시 만료 재설정
  },
  
  // 또는 Cloudflare Access 사용(독점 모드)
  cloudflareAccess: {
    teamDomain: "myteam.cloudflareaccess.com",
    audience: "your-app-audience-tag",
    autoProvision: true,
    defaultRole: 30,
    syncRoles: false,
    roleMapping: {
      "Admins": 50,
      "Editors": 40,
    },
  },
}

auth.selfSignup

이메일 도메인이 허용된 경우 사용자가 직접 등록할 수 있도록 허용합니다.

옵션유형기본값설명
domainsstring[][]허용된 이메일 도메인
defaultRolenumber20자체 가입 역할
selfSignup: {
  domains: ["example.com", "acme.org"],
  defaultRole: 20, // Contributor
}

auth.oauth

OAuth 로그인 공급자를 구성합니다.

oauth: {
  github: {
    clientId: process.env.GITHUB_CLIENT_ID,
    clientSecret: process.env.GITHUB_CLIENT_SECRET,
  },
  google: {
    clientId: process.env.GOOGLE_CLIENT_ID,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
  },
}

auth.session

세션 구성.

옵션유형기본값설명
maxAgenumber2592000 (30d)세션 수명(초)
slidingbooleantrue활동 시 만료 재설정

auth.cloudflareAccess

패스키 대신 Cloudflare Access를 인증 공급자로 사용합니다.

옵션유형기본값설명
teamDomainstring필수귀하의 Access 팀 도메인
audiencestring필수애플리케이션 Audience (AUD) 태그
autoProvisionbooleantrue첫 번째 로그인 시 사용자 생성
defaultRolenumber30새 사용자의 기본 역할
syncRolesbooleanfalse로그인할 때마다 역할 업데이트
roleMappingobjectIdP 그룹을 역할에 매핑

siteUrl

선택 사항. 사이트의 브라우저 지향 공개 오리진(스키마 + 호스트 + 선택적 포트, 경로 없음).

TLS 종료 역방향 프록시 뒤에서 Astro.url은 공개 주소(https://cms.example.com) 대신 내부 주소(http://localhost:4321)를 반환합니다. 이로 인해 패스키, CSRF 오리진 매칭, OAuth 리디렉션, 로그인 리디렉션, MCP 검색, 스냅샷 내보내기, sitemap, robots.txt 및 JSON-LD 구조화 데이터가 작동하지 않습니다. siteUrl을 설정하면 이 모든 문제를 한 번에 해결할 수 있습니다.

통합은 로드 시 이 값을 검증합니다: http: 또는 https: 프로토콜을 사용하는 유효한 URL이어야 하며 origin으로 정규화됩니다(경로는 제거됨).

emdash({
	database: sqlite({ url: "file:./data.db" }),
	storage: local({
		directory: "./uploads",
		baseUrl: "/_emdash/api/media/file",
	}),
	siteUrl: "https://cms.example.com",
});

구성에서 siteUrl이 설정되지 않은 경우 EmDash는 환경 변수를 순서대로 확인합니다: 먼저 EMDASH_SITE_URL, 그다음 SITE_URL. 이는 런타임에 공개 URL이 설정되는 컨테이너 배포에 유용합니다.

역방향 프록시 설정

Astro는 공개 호스트가 허용되는 경우에만 **X-Forwarded-***를 반영합니다. 사용자가 사용하는 호스트 이름(및 스키마)에 대해 security.allowedDomains를 구성하세요. **astro dev**에서 일치하는 **vite.server.allowedHosts**를 추가하여 Vite가 프록시 Host 헤더를 허용하도록 합니다.

allowedDomains(및 전달된 헤더)를 먼저 수정하는 것이 좋습니다. 재구성된 URL이 여전히 브라우저 오리진에서 벗어날 때 **siteUrl**을 사용하세요(일반적으로 TLS가 앞에서 종료되고 업스트림 요청이 **http://**로 유지되는 경우).

TLS를 앞에 두고 개발 서버를 루프백(astro dev --host 127.0.0.1)에 바인딩하는 것만으로도 충분합니다: 프록시는 로컬로 연결되고 **siteUrl**이 공개 HTTPS 오리진과 일치합니다.

import { defineConfig } from "astro/config";
import emdash, { local } from "emdash/astro";
import { sqlite } from "emdash/db";

export default defineConfig({
	security: {
		allowedDomains: [
			{ hostname: "cms.example.com", protocol: "https" },
			{ hostname: "cms.example.com", protocol: "http" },
		],
	},
	vite: {
		server: {
			allowedHosts: ["cms.example.com"],
		},
	},
	integrations: [
		emdash({
			database: sqlite({ url: "file:./data.db" }),
			storage: local({
				directory: "./uploads",
				baseUrl: "/_emdash/api/media/file",
			}),
			siteUrl: "https://cms.example.com",
		}),
	],
});

데이터베이스 어댑터

emdash/db에서 가져오기:

import { sqlite, libsql, postgres, d1 } from "emdash/db";

sqlite(config)

better-sqlite3을 사용하는 SQLite 데이터베이스.

옵션유형설명
urlstringfile: 접두어가 있는 파일 경로
sqlite({ url: "file:./data.db" });

libsql(config)

libSQL 데이터베이스.

옵션유형설명
urlstring데이터베이스 URL
authTokenstring인증 토큰(로컬 파일의 경우 선택 사항)
libsql({
	url: process.env.LIBSQL_DATABASE_URL,
	authToken: process.env.LIBSQL_AUTH_TOKEN,
});

postgres(config)

연결 풀링이 포함된 PostgreSQL 데이터베이스.

옵션유형설명
connectionStringstringPostgreSQL 연결 URL
hoststring데이터베이스 호스트
portnumber데이터베이스 포트
databasestring데이터베이스 이름
userstring데이터베이스 사용자
passwordstring데이터베이스 비밀번호
sslbooleanSSL 활성화
pool.minnumber최소 풀 크기(기본값: 0)
pool.maxnumber최대 풀 크기(기본값: 10)
postgres({ connectionString: process.env.DATABASE_URL });

d1(config)

Cloudflare D1 데이터베이스. @emdash-cms/cloudflare에서 가져옵니다.

옵션유형기본값설명
bindingstringwrangler.jsonc의 D1 바인딩 이름
sessionstring"disabled"읽기 복제 모드: "disabled", "auto" 또는 "primary-first"
bookmarkCookiestring"__ec_d1_bookmark"세션 북마크의 쿠키 이름
// 기본
d1({ binding: "DB" });

// 읽기 복제본 사용
d1({ binding: "DB", session: "auto" });

session"auto" 또는 "primary-first"인 경우 EmDash는 D1 Sessions API를 사용하여 읽기 쿼리를 근처 복제본으로 라우팅합니다. 인증된 사용자는 북마크 기반으로 쓴 내용을 읽을 수 있는 일관성을 갖습니다. 자세한 내용은 데이터베이스 옵션 — 읽기 복제본을 참조하세요.

스토리지 어댑터

emdash/astro에서 가져오기:

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

local(config)

로컬 파일 시스템 저장소.

옵션유형설명
directorystring디렉토리 경로
baseUrlstring파일 제공을 위한 기본 URL
local({
	directory: "./uploads",
	baseUrl: "/_emdash/api/media/file",
});

r2(config)

Cloudflare R2 바인딩.

옵션유형설명
bindingstringR2 바인딩 이름
publicUrlstring선택적 공개 URL
r2({
	binding: "MEDIA",
	publicUrl: "https://pub-xxxx.r2.dev",
});

s3(config?)

S3 호환 스토리지. 모든 구성 필드는 선택 사항입니다: s3({...})에서 생략된 필드는 Node 프로세스 시작 시 해당하는 S3_* 환경 변수에서 해석됩니다. 명시적 값이 항상 우선합니다.

전제 조건: 프로젝트에 @aws-sdk/client-s3@aws-sdk/s3-request-presigner를 설치하세요. EmDash 코어는 AWS SDK를 번들하지 않습니다. 자세한 내용은 스토리지 옵션 → S3 호환 스토리지를 참조하세요.

옵션유형설명
endpointstringS3 엔드포인트 URL (S3_ENDPOINT)
bucketstring버킷 이름 (S3_BUCKET)
accessKeyIdstring액세스 키 (S3_ACCESS_KEY_ID)
secretAccessKeystring비밀 키 (S3_SECRET_ACCESS_KEY)
regionstring지역, 기본값 "auto" (S3_REGION)
publicUrlstring선택적 CDN URL (S3_PUBLIC_URL)
// All fields from S3_* environment variables (Node container deployments)
s3()

// Mix: CDN from config, rest from environment
s3({ publicUrl: "https://cdn.example.com" })

// All explicit (unchanged from before)
s3({
	endpoint: "https://xxx.r2.cloudflarestorage.com",
	bucket: "media",
	accessKeyId: process.env.R2_ACCESS_KEY_ID,
	secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
	publicUrl: "https://cdn.example.com",
})

런타임 환경 변수 해석은 Node 전용 기능입니다. Cloudflare Workers에서는 시크릿과 변수가 process.env가 아닌 fetch 핸들러의 env 매개변수를 통해 노출되므로 S3_* 환경 변수가 읽히지 않습니다. Workers 배포에서는 r2(config) 어댑터를 사용하거나 s3({...})에 명시적 값을 전달해야 합니다. 자세한 내용은 스토리지 옵션을 참조하세요.

라이브 컬렉션

src/live.config.ts에서 EmDash 로더를 구성합니다:

import { defineLiveCollection } from "astro:content";
import { emdashLoader } from "emdash/runtime";

export const collections = {
	_emdash: defineLiveCollection({
		loader: emdashLoader(),
	}),
};

로더 옵션

emdashLoader() 함수는 선택적 구성을 허용합니다:

emdashLoader({
	// 현재 옵션 없음 - 향후 사용을 위해 예약됨
});

환경 변수

EmDash는 다음 환경 변수를 사용합니다:

변수설명
EMDASH_SITE_URL브라우저 지향 공개 오리진 (SITE_URL로 폴백)
EMDASH_DATABASE_URL데이터베이스 URL 재정의
EMDASH_AUTH_SECRET패스키 인증을 위한 시크릿
EMDASH_PREVIEW_SECRET미리보기 토큰 생성을 위한 시크릿
EMDASH_URL스키마 동기화를 위한 원격 EmDash URL

다음을 사용하여 인증 시크릿을 생성합니다:

npx emdash auth secret

package.json 구성

package.json의 선택적 구성:

{
	"emdash": {
		"label": "My Blog Template",
		"description": "A clean, minimal blog template",
		"seed": ".emdash/seed.json",
		"url": "https://my-site.pages.dev",
		"preview": "https://emdash-blog.pages.dev"
	}
}
옵션설명
label표시용 템플릿 이름
description템플릿 설명
seed시드 JSON 파일의 경로
url스키마 동기화를 위한 원격 URL
preview템플릿 미리보기를 위한 데모 사이트 URL

TypeScript 구성

EmDash는 .emdash/types.ts에서 타입을 생성합니다. tsconfig.json에 다음을 추가하세요:

{
	"compilerOptions": {
		"paths": {
			"@emdash-cms/types": ["./.emdash/types.ts"]
		}
	}
}

다음을 사용하여 타입을 생성합니다:

npx emdash types