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

서버는 기본적으로 http://localhost:4321에서 실행됩니다. 기본 auto 마이그레이션 모드에서는 첫 번째 요청이 대기 중인 코어 마이그레이션을 적용합니다. 새 데이터베이스에는 내장된 시드도 적용됩니다. 코어 데이터베이스 마이그레이션 관리에서 프로덕션 트래픽을 재개하기 전에 마이그레이션하는 방법을 설명합니다.

예약 작업

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

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

플러그인 샌드박스

마켓플레이스 플러그인과 sandboxed: []에 나열된 플러그인에는 샌드박스 러너가 필요합니다. Node.js에서 러너는 @emdash-cms/sandbox-workerd이며, workerd 자식 프로세스에서 플러그인을 실행합니다. 플러그인 샌드박스에서 설치, 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는 현재 플러그인 시크릿이나 기타 저장된 데이터를 암호화하지 않습니다. 변수가 설정되면 EmDash가 시작 시 형식을 확인하지만, 플러그인 시크릿 값은 데이터베이스에 평문으로 남아 있습니다.

변수를 설정하는 경우 유효한 값을 생성하고 결과를 환경에 추가합니다:

npx emdash secrets generate  # 결과를 환경에 추가

이 값은 운영자가 제공하며 데이터베이스에 저장되지 않습니다. 분실해도 저장된 데이터가 이에 의존하지 않으므로 데이터 복구에 영향이 없습니다. 데이터베이스와 백업에는 평문 플러그인 시크릿이 포함되어 있으므로 민감하게 취급하세요.

선택 사항: 안정적인 값 재정의

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

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

키 형식, 지원되는 모든 시크릿, 순환 또는 분실의 효과는 시크릿 및 키 관리를 참조하세요.

데이터베이스 및 스토리지

변수설명예시
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 파일과 업로드 디렉토리를 모두 백업하세요. 복구 중 교체하기 전에 프로세스를 중지하세요. 백업을 참조하세요.

상태 확인

로드 밸런서용 상태 확인 엔드포인트를 추가합니다:

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. 사이트가 샌드박스 플러그인을 사용하는 경우 플러그인 라우트 또는 훅을 호출하고 서버 로그에 샌드박스 사용 불가 또는 workerd 시작 오류가 없는지 확인합니다.

적용 가능한 모든 검사를 통과할 때까지 새 인스턴스를 로드 밸런서에서 제외하세요.