Implantar no Node.js

Nesta página

O EmDash roda no Node.js 22.16 ou posterior. Este guia usa SQLite com armazenamento local ou compatível com S3; libSQL e PostgreSQL funcionam da mesma forma no Node.js — veja Opções de banco de dados.

Pré-requisitos

  • Node.js v22.16.0 ou superior
  • Um provedor de hospedagem Node.js ou VPS

Configuração

Configure o EmDash para implantação no Node.js:

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",
			}),
		}),
	],
});

Compilar e executar

  1. Compilar o projeto:

    npm run build
  2. Iniciar o servidor:

    node ./dist/server/entry.mjs

O servidor roda em http://localhost:4321 por padrão. As migrações são aplicadas na primeira requisição. Se o banco de dados estiver vazio e a configuração não tiver sido concluída, seu arquivo seed (ou o padrão integrado se você não tiver um) também é aplicado nessa primeira requisição.

Tarefas agendadas

O agendador integrado roda apenas enquanto um processo Node.js está em execução. Ele lida com publicação agendada, tarefas de plugins e manutenção geral.

Mantenha pelo menos um processo Node.js rodando continuamente em produção. As tarefas agendadas pausam quando todos os processos param ou entram em modo de suspensão.

Sandbox de plugins

Os plugins do marketplace e os listados sob sandboxed: [] precisam de um runner de sandbox. No Node.js, o runner é @emdash-cms/sandbox-workerd, que executa plugins em um processo filho workerd. Plugin Sandbox cobre a instalação, como o processo workerd funciona e seus modos de falha.

Armazenamento de produção

Para produção, use armazenamento compatível com S3 em vez do sistema de arquivos local:

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

export default defineConfig({
	integrations: [
		emdash({
			database: sqlite({ url: `file:${process.env.DATABASE_PATH}` }),
			storage: s3({
				endpoint: process.env.S3_ENDPOINT,
				bucket: process.env.S3_BUCKET,
				accessKeyId: process.env.S3_ACCESS_KEY_ID,
				secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
				publicUrl: process.env.S3_PUBLIC_URL, // URL CDN opcional
			}),
		}),
	],
});

Docker

Adicione um .dockerignore para manter o contexto de build pequeno:

node_modules
dist
.git

Crie um 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"]

O arquivo seed é lido no momento do build e incorporado no bundle, então não precisa ser copiado para a imagem de runtime. As migrações são executadas na primeira requisição após uma implantação; o seed é aplicado apenas quando o banco de dados não tem coleções e a configuração não foi concluída — dados existentes nunca são sobrescritos.

Construa a imagem e execute o container:

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

Um arquivo Docker Compose gerencia o mesmo container com um volume nomeado:

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

volumes:
  emdash-data:

Inicie a stack em segundo plano:

docker compose up -d

Variáveis de ambiente

Recomendado: chave de criptografia

EMDASH_ENCRYPTION_KEY é a chave para criptografar os segredos dos plugins em repouso. A chave é validada na inicialização; a criptografia de segredos de plugins a usa uma vez habilitada. Defina-a em cada implantação para que os segredos fiquem protegidos sem uma alteração de configuração posterior.

Gere uma chave e adicione o resultado ao seu ambiente:

npx emdash secrets generate  # adicione o resultado ao seu ambiente

A chave é fornecida por você e nunca armazenada no banco de dados; apenas texto cifrado é armazenado. Faça backup em um local durável (um gerenciador de senhas, KMS ou o cofre de segredos da sua equipe) — perdê-la significa perder cada segredo criptografado com ela.

Opcional: overrides de valor estável

O EmDash auto-gera o segredo HMAC de preview e o salt de hash de IP do comentarista e os persiste no banco de dados no primeiro uso. As variáveis de ambiente abaixo os fixam a um valor que você controla — útil quando um processo separado precisa compartilhar um segredo com seu site principal.

VariávelDescrição
EMDASH_PREVIEW_SECRETOverride para o segredo HMAC de preview auto-gerado.
EMDASH_IP_SALTOverride para o salt de hash de IP do comentarista auto-gerado.
EMDASH_AUTH_SECRETOpcional. Se definido, usado como fonte do salt de IP (a menos que EMDASH_IP_SALT também esteja definido, que tem precedência), mantendo os hashes de IP estáveis para instalações que já dependem dele. Deixe sem definir para uma nova implantação.

Banco de dados e armazenamento

VariávelDescriçãoExemplo
DATABASE_PATHCaminho para banco SQLite/data/emdash.db
HOSTHost do servidor0.0.0.0
PORTPorta do servidor4321
S3_ENDPOINTURL do endpoint S3https://xxx.r2.cloudflarestorage.com
S3_BUCKETNome do bucket S3my-media-bucket
S3_ACCESS_KEY_IDChave de acesso S3AKIA...
S3_SECRET_ACCESS_KEYChave secreta S3...
S3_PUBLIC_URLURL pública para mídiahttps://cdn.example.com

Armazenamento persistente

O SQLite requer armazenamento de disco persistente. Certifique-se de que sua plataforma de hospedagem forneça:

  • Um volume montado ou disco persistente
  • Acesso de escrita ao diretório do banco de dados
  • Mecanismos de backup para o arquivo do banco de dados

Verificações de saúde

Adicione um endpoint de verificação de saúde para balanceadores de carga:

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

Configure sua plataforma para verificar /health para sondas de liveness.