# 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.

Source: https://emdashcmseverything.com/docs/emdash-cms-self-hosted-node-deployment-reference/

- Published: 2026-04-08

## 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.

## Recommended progression model

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.

```bash
# 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.
