Emdash CMS Self-Hosted Node Deployment Reference

Run EmDash on your own infrastructure with a progressive architecture path from SQLite to PostgreSQL and object storage.

When self-hosting is the right choice

Choose self-hosting when your constraints are operational, legal, or architectural:

  • data residency requirements are strict
  • you already run shared platform services internally
  • you need full control over runtime, process model, and network paths
  • you want to avoid managed-cloud coupling in early stages

Self-hosting is not automatically cheaper. It is usually more controllable.

Do not start with maximum complexity. Use a staged rollout:

  1. Node.js + SQLite + local file storage
  2. PostgreSQL for multi-instance safety and stronger durability
  3. S3-compatible object storage for media portability
  4. process supervision and observability hardening

This sequence minimizes migration shock while preserving a clean production path.

Baseline architecture (Stage 1)

For single-node production or early launch:

  • app runtime: Node adapter (standalone)
  • database: SQLite file on persistent disk
  • media: local uploads directory
  • reverse proxy: Nginx or Caddy

This setup is sufficient for low to moderate editorial workloads with one runtime instance.

# Production build and run
npm install
npm run build
npm run start

Stage 2 upgrade criteria (move to PostgreSQL)

Upgrade database when any of these appear:

  • concurrent write contention becomes frequent
  • backup/recovery objectives exceed file-copy strategy
  • you need safer multi-instance deployment

Use PostgreSQL before adding horizontal app scaling. Scaling app nodes on SQLite creates operational risk quickly.

Storage strategy: local files vs object storage

Local files (start here)

Good for single-instance environments with predictable storage growth.

S3-compatible object storage (move here for scale)

Use when:

  • multiple app instances need shared media access
  • backup and disaster recovery must be standardized
  • CDN and edge cache strategy depends on stable object URLs

MinIO can be used on private infrastructure for S3-compatible behavior.

Runtime process and proxy baseline

Process management

Use one of:

  • systemd for Linux-native service control
  • pm2 for teams wanting process metrics and quick restarts

Reverse proxy

Terminate TLS at proxy and forward to Node app:

  • preserve Host and X-Forwarded-* headers
  • configure health check path
  • set body size limits aligned with upload policy

Backup and recovery policy

Treat backup policy as launch-blocking, not a post-launch task.

Minimum baseline:

  • database snapshots on schedule
  • media storage backups or replication
  • restore drill at least once before public launch

A backup that has never been restored in testing is a rumor, not a control.

Operational readiness checklist

Before production cutover, confirm:

  • cold restart works with no manual edits
  • application logs are centralized and searchable
  • 5xx alerting is active
  • disk usage and storage growth are monitored
  • secret rotation process is documented

Migration notes from Cloudflare-oriented setup

If your project began with Cloudflare assumptions:

  • remove cloud-only bindings from runtime config
  • replace D1/R2 adapters with Node-compatible database and storage adapters
  • revalidate auth and callback URLs behind your reverse proxy

Migration risk is mostly in environment assumptions, not in page-level code.

Decision framework for teams

Use this rule:

  • if you need speed and minimal ops, prefer managed cloud path
  • if you need control and integration with existing infra, prefer self-hosted path

Pick one default path per environment. Hybrid deployment models are possible, but they increase cognitive load and support burden.