Node.js에 배포

이 페이지

EmDash는 Node.js 22.16 이상에서 실행됩니다. 이 가이드는 한 서버에 SQLite와 로컬 스토리지를 사용합니다. 여러 인스턴스가 하나의 데이터베이스를 필요로 하면 PostgreSQL 또는 libSQL을 쓰고, 미디어가 서버 디스크와 독립적으로 살아남아야 하면 S3 호환 스토리지를 사용하세요.

사전 요구 사항

  • Node.js v22.16.0 이상
  • Node.js 호스팅 제공자 또는 VPS

사이트 구성

Node.js 배포용으로 EmDash를 구성하세요.

import { defineConfig } from "astro/config";
import node from "@astrojs/node";
import emdash, { local, s3 } from "emdash/astro";
import { sqlite } from "emdash/db";

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

빌드 및 실행

  1. 프로젝트를 빌드합니다.

    npm run build
  2. 서버를 시작합니다.

    node ./dist/server/entry.mjs

    서버를 시작하기 전에 호스팅 제공자의 프로세스 환경을 통해 EMDASH_ENCRYPTION_KEY와 기타 런타임 자격 증명을 설정하세요. 독립형 Node 엔트리는 .env를 자동으로 로드하지 않습니다. 생성된 .env 파일을 사용하는 로컬 실행은 node --env-file=.env ./dist/server/entry.mjs로 시작하세요.

서버는 기본적으로 http://localhost:4321에서 실행됩니다. 기본 auto 마이그레이션 모드에서는 첫 요청이 대기 중인 코어 마이그레이션을 적용합니다. 새 데이터베이스는 임베디드 시드도 받습니다. Manage core database migrations는 프로덕션 트래픽을 재개하기 전에 마이그레이션하는 방법을 설명합니다.

예약 작업

내장 스케줄러는 Node.js 프로세스가 실행 중일 때만 동작합니다. 예약 게시, 플러그인 작업, 일반 유지보수를 처리합니다.

프로덕션에서는 최소 하나의 Node.js 프로세스를 지속적으로 실행하세요. 모든 프로세스가 중지되거나 슬립하면 예약 작업이 일시 중지됩니다.

플러그인 샌드박스

마켓플레이스 플러그인과 sandboxed: [] 아래 나열된 플러그인에는 샌드박스 러너가 필요합니다. Node.js에서 러너는 @emdash-cms/sandbox-workerd이며, 플러그인을 workerd 자식 프로세스에서 실행합니다. Plugin Sandbox는 설치, workerd 프로세스 동작, 실패 모드를 다룹니다.

프로덕션 데이터 서비스 선택

데이터베이스가 영속 볼륨에 남고 미디어가 S3 호환 스토리지로 이동할 때 다음 패턴을 사용하세요.

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

export default defineConfig({
	integrations: [
			emdash({
				database: sqlite({ url: `file:${process.env.DATABASE_PATH}` }),
				storage: s3(),
		}),
	],
});

Docker

빌드 컨텍스트를 작게 유지하려면 .dockerignore를 추가하세요.

node_modules
dist
.git

Dockerfile을 만드세요.

FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:22-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./

RUN mkdir -p data

ENV HOST=0.0.0.0
ENV PORT=4321

EXPOSE 4321
CMD ["node", "./dist/server/entry.mjs"]

시드 파일은 빌드 시 읽혀 번들에 인라인되므로 런타임 이미지에 복사할 필요가 없습니다. 마이그레이션은 배포 후 첫 요청에서 실행되며, 시드는 데이터베이스에 컬렉션이 없고 설정이 완료되지 않았을 때만 적용됩니다 — 기존 데이터는 절대 덮어쓰지 않습니다.

이미지를 빌드하고 컨테이너를 실행하세요.

docker build -t my-emdash-site .
docker run -p 4321:4321 -v emdash-data:/app/data my-emdash-site

Docker Compose 파일은 명명된 볼륨으로 같은 컨테이너를 관리합니다.

services:
  emdash:
    build: .
    ports:
      - "4321:4321"
    volumes:
      - emdash-data:/app/data
    restart: unless-stopped

volumes:
  emdash-data:

스택을 백그라운드에서 시작하세요.

docker compose up -d

런타임 환경

서버가 시작될 때 프로세스 환경에서 데이터베이스와 스토리지 자격 증명을 읽습니다. 다음 변수가 위 구성을 지원합니다.

플러그인 설정 암호화

EMDASH_ENCRYPTION_KEY는 시크릿으로 선언된 플러그인 설정을 암호화합니다. 잘못된 값은 운영자 대상 시작 메시지를 만들고, 값이 수정될 때까지 플러그인 시크릿 설정 작업이 실패합니다.

유효한 값을 생성하고 결과를 서버 프로세스 환경에 추가하세요.

npx emdash secrets generate  # add the result to your environment

값은 운영자가 제공하며 데이터베이스에 저장되지 않습니다. 시크릿 매니저와 별도의 복구 백업에 보관하세요. 로테이션 중에는 먼저 새 키를 제공하고, 모든 플러그인 시크릿이 다시 저장될 때까지 쉼표 뒤에 이전 키를 유지하세요. EmDash는 현재 어떤 키 ID가 사용 중인지 보고하지 않으므로, 다시 저장한 각 자격 증명을 추적하고 이전 키를 제거하기 전에 통합을 확인하세요. 참조된 키 없이 데이터베이스를 복원하면 해당 설정을 읽을 수 없게 됩니다.

선택: 안정 값 오버라이드

EmDash는 미리보기 HMAC 시크릿과 댓글 작성자 IP 해시 솔트를 자동 생성하고 첫 사용 시 데이터베이스에 유지합니다. 아래 환경 변수는 이를 제어하는 값으로 고정합니다 — 별도 프로세스가 메인 사이트와 시크릿을 공유해야 할 때 유용합니다.

변수설명
EMDASH_PREVIEW_SECRET자동 생성 미리보기 HMAC 시크릿 오버라이드.
EMDASH_IP_SALT자동 생성 댓글 작성자 IP 해시 솔트 오버라이드.
EMDASH_AUTH_SECRET선택. 설정되면 IP 솔트 소스로 사용됩니다(EMDASH_IP_SALT도 설정되면 그쪽이 우선). 이미 이에 의존하는 설치에서 댓글 작성자 IP 해시를 안정적으로 유지합니다. 새 배포에서는 설정하지 마세요.

키 형식, 지원되는 모든 시크릿, 로테이션이나 손실의 영향은 Secrets and key management를 참고하세요.

데이터베이스와 스토리지

변수설명예
DATABASE_PATHSQLite 데이터베이스 경로/data/emdash.db
HOST서버 호스트0.0.0.0
PORT서버 포트4321
S3_ENDPOINTS3 엔드포인트 URLhttps://xxx.r2.cloudflarestorage.com
S3_BUCKETS3 버킷 이름my-media-bucket
S3_ACCESS_KEY_IDS3 액세스 키AKIA...
S3_SECRET_ACCESS_KEYS3 시크릿 키...
S3_REGIONS3 리전auto
S3_PUBLIC_URL미디어 공개 URLhttps://cdn.example.com

영속 스토리지

SQLite에는 영속 디스크 스토리지가 필요합니다. 호스팅 플랫폼이 다음을 제공하는지 확인하세요.

  • 마운트된 볼륨 또는 영속 디스크
  • 데이터베이스 디렉터리에 대한 쓰기 접근
  • 데이터베이스 파일 백업 메커니즘

SQLite 파일과 업로드 디렉터리 모두를 백업하세요. 복구 중 어느 하나를 교체하기 전에 프로세스를 중지하세요. Backups를 참고하세요.

헬스 체크

로드 밸런서를 위한 헬스 체크 엔드포인트를 추가하세요.

export const GET = () => {
  return new Response("OK", { status: 200 });
};

이 엔드포인트는 Node.js 프로세스가 Astro 라우트를 제공할 수 있음을 증명합니다. 데이터베이스, 스토리지 백엔드, 마이그레이션 상태, 플러그인 샌드박스가 건강한지는 증명하지 않습니다. 새 릴리스에 트래픽을 보내기 전에 해당 의존성을 별도로 확인하세요.

트래픽을 보내기 전에 확인

새 빌드를 시작한 후, 프로덕션 요청이 사용하는 것과 같은 런타임 서비스를 확인하세요.

  1. /health와 공개 콘텐츠 페이지를 요청합니다. 둘 다 성공 응답을 반환해야 합니다.
  2. 빌드된 프로젝트에서 npx emdash migrate --check를 실행합니다. 구성된 데이터베이스에 대기 중이거나 알 수 없는 마이그레이션이 없다고 보고해야 합니다.
  3. /_emdash/admin에 로그인하고 일회용 초안을 만들거나 편집한 뒤 게시합니다. 공개 페이지에 변경이 표시되는지 확인합니다.
  4. 일회용 미디어 파일을 업로드하고 반환된 URL을 엽니다. 확인 후 파일을 삭제합니다.
  5. 사이트가 샌드박스 플러그인을 사용하면 플러그인 라우트나 훅 하나를 호출하고 서버 로그에 sandbox-unavailable 또는 workerd 시작 오류가 없는지 확인합니다.

적용되는 모든 검사가 통과할 때까지 새 인스턴스를 로드 밸런서 밖에 두세요.