EmDash funziona su Node.js 22.16 o successivo. Questa guida usa SQLite con storage locale o compatibile S3; libSQL e PostgreSQL funzionano allo stesso modo su Node.js — vedi Opzioni database.
Prerequisiti
- Node.js v22.16.0 o superiore
- Un provider di hosting Node.js o VPS
Configurazione
Configura EmDash per il deployment su 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",
}),
}),
],
});
Compilazione ed esecuzione
-
Compila il progetto:
npm run build -
Avvia il server:
node ./dist/server/entry.mjs
Il server gira su http://localhost:4321 per impostazione predefinita. Le migrazioni vengono applicate alla prima richiesta. Se il database è vuoto e il setup non è stato completato, il file seed (o quello predefinito integrato se non ne hai uno) viene applicato anch’esso alla prima richiesta.
Attività pianificate
Lo scheduler integrato funziona solo mentre un processo Node.js è in esecuzione. Gestisce la pubblicazione pianificata, le attività dei plugin e la manutenzione generale.
Mantieni almeno un processo Node.js in esecuzione continua in produzione. Le attività pianificate si mettono in pausa quando tutti i processi si fermano o vanno in sleep.
Sandbox dei plugin
I plugin del marketplace e quelli elencati sotto sandboxed: [] necessitano di un runner sandbox. Su Node.js, il runner è @emdash-cms/sandbox-workerd, che esegue i plugin in un processo figlio workerd. Plugin Sandbox copre l’installazione, come funziona il processo workerd e le sue modalità di errore.
Storage di produzione
Per la produzione, usa storage compatibile S3 invece del filesystem locale:
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 opzionale
}),
}),
],
});
Docker
Aggiungi un .dockerignore per mantenere piccolo il contesto di build:
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"]
Il file seed viene letto al momento del build e incorporato nel bundle, quindi non ha bisogno di essere copiato nell’immagine di runtime. Le migrazioni vengono eseguite alla prima richiesta dopo un deploy; il seed viene applicato solo quando il database non ha collezioni e il setup non è stato completato — i dati esistenti non vengono mai sovrascritti.
Costruisci l’immagine e avvia il container:
docker build -t my-emdash-site .
docker run -p 4321:4321 -v emdash-data:/app/data my-emdash-site
Un file Docker Compose gestisce lo stesso container con un volume nominato:
services:
emdash:
build: .
ports:
- "4321:4321"
volumes:
- emdash-data:/app/data
restart: unless-stopped
volumes:
emdash-data:
Avvia lo stack in background:
docker compose up -d
Variabili d’ambiente
Consigliato: chiave di crittografia
EMDASH_ENCRYPTION_KEY è la chiave per crittografare i segreti dei plugin a riposo. La chiave viene validata all’avvio; la crittografia dei segreti dei plugin la usa una volta abilitata. Impostala ad ogni deployment così i segreti sono protetti senza un cambio di configurazione successivo.
Genera una chiave e aggiungi il risultato al tuo ambiente:
npx emdash secrets generate # aggiungi il risultato al tuo ambiente
La chiave è fornita da te e mai memorizzata nel database; solo il testo cifrato viene memorizzato. Esegui il backup in un luogo durevole (un gestore di password, KMS o il vault dei segreti del tuo team) — perderla significa perdere ogni segreto crittografato con essa.
Opzionale: override di valore stabile
EmDash auto-genera il segreto HMAC di preview e il salt di hash IP del commentatore e li persiste nel database al primo utilizzo. Le variabili d’ambiente sottostanti li fissano a un valore che controlli — utile quando un processo separato deve condividere un segreto con il tuo sito principale.
| Variabile | Descrizione |
|---|---|
EMDASH_PREVIEW_SECRET | Override per il segreto HMAC di preview auto-generato. |
EMDASH_IP_SALT | Override per il salt di hash IP del commentatore auto-generato. |
EMDASH_AUTH_SECRET | Opzionale. Se impostato, usato come fonte del salt IP (a meno che non sia impostato anche EMDASH_IP_SALT, che ha precedenza), mantenendo gli hash IP stabili per le installazioni che già dipendono da esso. Lascialo non impostato per un nuovo deployment. |
Database e storage
| Variabile | Descrizione | Esempio |
|---|---|---|
DATABASE_PATH | Percorso al database SQLite | /data/emdash.db |
HOST | Host del server | 0.0.0.0 |
PORT | Porta del server | 4321 |
S3_ENDPOINT | URL dell’endpoint S3 | https://xxx.r2.cloudflarestorage.com |
S3_BUCKET | Nome del bucket S3 | my-media-bucket |
S3_ACCESS_KEY_ID | Chiave di accesso S3 | AKIA... |
S3_SECRET_ACCESS_KEY | Chiave segreta S3 | ... |
S3_PUBLIC_URL | URL pubblica per i media | https://cdn.example.com |
Storage persistente
SQLite richiede storage su disco persistente. Assicurati che la tua piattaforma di hosting fornisca:
- Un volume montato o disco persistente
- Accesso in scrittura alla directory del database
- Meccanismi di backup per il file del database
Controlli di salute
Aggiungi un endpoint di controllo salute per i bilanciatori di carico:
export const GET = () => {
return new Response("OK", { status: 200 });
};
Configura la tua piattaforma per verificare /health per i probe di liveness.