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.
Recommended progression model
Do not start with maximum complexity. Use a staged rollout:
- Node.js + SQLite + local file storage
- PostgreSQL for multi-instance safety and stronger durability
- S3-compatible object storage for media portability
- 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:
systemdfor Linux-native service controlpm2for teams wanting process metrics and quick restarts
Reverse proxy
Terminate TLS at proxy and forward to Node app:
- preserve
HostandX-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.