EmDash se ejecuta en cualquier plataforma de hosting Node.js 22+. Esta guía usa SQLite con almacenamiento local o compatible con S3; libSQL y PostgreSQL funcionan de la misma manera en Node.js — consulta Opciones de base de datos.
Requisitos previos
- Node.js v22.12.0 o superior
- Un proveedor de hosting Node.js o VPS
Configuración
Configura EmDash para despliegue en 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 y ejecutar
-
Compilar el proyecto:
npm run build -
Iniciar el servidor:
node ./dist/server/entry.mjs
El servidor se ejecuta en http://localhost:4321 por defecto. Las migraciones se aplican en la primera solicitud. Si la base de datos está vacía y la configuración no se ha completado, tu archivo seed (o el predeterminado integrado si no tienes uno) también se aplica en esa primera solicitud.
Almacenamiento de producción
Para producción, usa almacenamiento compatible con S3 en lugar del sistema de archivos 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
Añade un .dockerignore para mantener el contexto de compilación pequeño:
node_modules
dist
.git
Crea un 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"]
El archivo seed se lee en tiempo de compilación y se incluye en el bundle, por lo que no necesita copiarse en la imagen de runtime. Las migraciones se ejecutan en la primera solicitud después de un despliegue; el seed solo se aplica cuando la base de datos no tiene colecciones y la configuración no se ha completado — los datos existentes nunca se sobrescriben.
Si encuentras ese error, instala el toolchain en la fase builder antes de npm ci:
# Imágenes basadas en Alpine (node:22-alpine)
RUN apk add --no-cache python3 make g++
# Imágenes basadas en Debian (node:22-slim)
RUN apt-get update && apt-get install -y --no-install-recommends python3 make g++ \
&& rm -rf /var/lib/apt/lists/*
Compilar la imagen y ejecutar el contenedor:
docker build -t my-emdash-site .
docker run -p 4321:4321 -v emdash-data:/app/data my-emdash-site
Un archivo Docker Compose gestiona el mismo contenedor con un volumen con nombre:
services:
emdash:
build: .
ports:
- "4321:4321"
volumes:
- emdash-data:/app/data
restart: unless-stopped
volumes:
emdash-data:
Iniciar el stack en segundo plano:
docker compose up -d
Variables de entorno
Recomendado: clave de cifrado
EMDASH_ENCRYPTION_KEY es la clave para cifrar los secrets de plugins en
reposo. La clave se valida al iniciar; el cifrado de secrets de plugins la
usa una vez habilitado. Configúrala en cada despliegue para que los secrets estén protegidos
sin un cambio de configuración posterior.
Genera una clave y añade el resultado a tu entorno:
npx emdash secrets generate # añade el resultado a tu entorno
La clave la proporcionas tú y nunca se almacena en la base de datos; solo se almacena texto cifrado. Resguárdala en un lugar duradero (gestor de contraseñas, KMS o almacén de secrets de tu equipo) — perderla significa perder cada secret cifrado con ella.
Opcional: sobrescrituras de valores estables
EmDash auto-genera el secret HMAC de preview y el salt de hash de IP de comentaristas y los persiste en la base de datos en el primer uso. Las variables de entorno a continuación los fijan a un valor que tú controlas — útil cuando un proceso separado necesita compartir un secret con tu sitio principal.
| Variable | Descripción |
|---|---|
EMDASH_PREVIEW_SECRET | Sobrescritura para el secret HMAC de preview auto-generado. |
EMDASH_IP_SALT | Sobrescritura para el salt de hash de IP de comentaristas auto-generado. |
EMDASH_AUTH_SECRET | Opcional. Si se establece, se usa como fuente de salt de IP (a menos que EMDASH_IP_SALT también esté establecido, que tiene precedencia), manteniendo los hashes de IP de comentaristas estables para instalaciones que ya dependen de él. Déjalo sin establecer para un nuevo despliegue. |
Base de datos y almacenamiento
| Variable | Descripción | Ejemplo |
|---|---|---|
DATABASE_PATH | Ruta a la base de datos SQLite | /data/emdash.db |
HOST | Host del servidor | 0.0.0.0 |
PORT | Puerto del servidor | 4321 |
S3_ENDPOINT | URL del endpoint S3 | https://xxx.r2.cloudflarestorage.com |
S3_BUCKET | Nombre del bucket S3 | my-media-bucket |
S3_ACCESS_KEY_ID | Clave de acceso S3 | AKIA... |
S3_SECRET_ACCESS_KEY | Clave secreta S3 | ... |
S3_PUBLIC_URL | URL pública para medios | https://cdn.example.com |
Almacenamiento persistente
SQLite requiere almacenamiento en disco persistente. Asegúrate de que tu plataforma de hosting proporcione:
- Un volumen montado o disco persistente
- Acceso de escritura al directorio de la base de datos
- Mecanismos de respaldo para el archivo de base de datos
Health Checks
Añade un endpoint de health check para balanceadores de carga:
export const GET = () => {
return new Response("OK", { status: 200 });
};
Configura tu plataforma para verificar /health para sondas de vivacidad.