Choose Your Install Path
| Path | Best for | SSH needed? | Where the build runs | Process kept running by |
|---|---|---|---|---|
| Path 1: cPanel server or shared hosting | cPanel accounts with Node.js App | No, but helpful | Your computer or the app manager | cPanel Node.js App (Passenger) |
| Path 2: UnderHost shared hosting | UnderHost shared plans, testing and small sites | No | Your computer (recommended) or app manager | cPanel Node.js App; may idle |
| Path 3: Linux server, no panel | VPS or dedicated server with root | Yes | The server | systemd, pm2 or Docker |
| Cloudflare Workers (alternative) | No server to manage | No (Wrangler on your computer) | Your computer | Cloudflare Workers |
For production sites with scheduled publishing, a server where you control the process (Path 3, or a Cloud VPS) is the safer choice. Shared hosting is suitable for a test site or a small site that does not rely on scheduled posts.
Step 0: Build the Project Locally
Build and test the site on your own computer first. EmDash’s Node.js guide starts with the scaffolder, and the same project works on every path below.
- Check Node.js: run
node --version. It must report v22.16.0 or later. - Create the project: run
npm create emdash@latest. When asked where you will deploy, choose Node.js. Choose the Starter template, which the docs show with Posts and Pages. - Run it locally: run
npm run dev, then openhttp://localhost:4321/_emdash/admin/and complete the setup wizard. - Generate the encryption key: run
npx emdash secrets generateand save the output. It encrypts plugin secrets. Keep a separate backup of it, because the docs say you cannot recover stored plugin secrets without it. - Set the site URL: set
EMDASH_SITE_URLto your public address, for examplehttps://example.com. It must be set at build time, or images are served unoptimised.
Do not upload your .env file:
The scaffolder writes the encryption key to a .env file. Keep .env out of uploads and out of version control. Set the same variables in your hosting panel or server environment instead.
Steps Every Path Shares
These requirements come from EmDash’s Node.js deployment guide. They apply to every path.
| Requirement | Setting | Notes from the docs |
|---|---|---|
| Node.js 22.16 or later | Node version in the host, or your server | Required. Check the version before you start. |
| Build step | npm run build, with EMDASH_SITE_URL set | Produces dist/server/entry.mjs. |
| Start command | node ./dist/server/entry.mjs | Standalone Node entry. It does not read a .env file, so set variables in the environment. |
| Encryption key | EMDASH_ENCRYPTION_KEY | Required for plugin secrets. Generate with npx emdash secrets generate. |
| Database | DATABASE_PATH, for example /home/you/emdash/data/emdash.db | SQLite needs persistent disk and write access to the folder. |
| Uploads | Local directory ./data/uploads, or S3/R2 storage | Back up the upload folder with the database. |
| Address and port | HOST and PORT (default 4321) | On a panel, the app manager may assign the port. Follow its instructions. |
| HTTPS | Reverse proxy, panel SSL, or Cloudflare | Set EMDASH_SITE_URL so absolute URLs are correct. |
Path 1: cPanel Server or Shared Hosting (Node.js App)
Use this path on a cPanel account with a Setup Node.js App tool. The menu labels below follow common cPanel wording. Your screen may differ, so match the steps to the fields you see.
- Create the app. In Setup Node.js App, choose Create Application. Set the Node.js version to 22.16 or later. Set the application root to a folder such as
emdash. Set the application URL to your domain or subdomain. - Set the startup file. Set it to
dist/server/entry.mjs, which EmDash’s docs start withnode. If the manager rejects an .mjs file, ask UnderHost support whether it can run an ES module, and test before going further. - Upload the project. Upload your project folder through File Manager as a zip, then extract it in the application root. Do not upload node_modules or .env. Upload dist/ only if you build on your computer.
- Install and build. Use Run NPM Install in the app manager if it is offered, then run the build. If the app manager cannot run the build, build on your computer and upload dist/ and the packages it needs (see the note below).
- Set environment variables. Add EMDASH_ENCRYPTION_KEY, EMDASH_SITE_URL and DATABASE_PATH in the app manager. Add HOST if the manager asks for it. Do not set PORT yourself unless the manager tells you to, because it assigns the port.
- Create the data folders. In File Manager, create the folder for the database and the uploads folder. Make sure the app can write to them.
- Start the app. Restart it from the app manager. Then open your domain and check the checks in the section below.
Path 2: UnderHost Shared Hosting Without SSH
This is the same app-manager route as Path 1, with shared-plan limits. UnderHost shared plans include Node.js and crontab and do not include SSH, so you do everything in cPanel and File Manager.
- Build on your computer. Without SSH, the build is the step most likely to fail on shared hosting. Build with
npm run buildon your computer, then upload dist/ and the runtime packages. - Test the process. Check whether the app stays running between visits. EmDash’s docs say scheduled publishing pauses when no process runs, so test a scheduled post before you rely on it.
- Keep the data small. Shared plans have disk and bandwidth limits, and the SQLite file and uploads grow with content. Check your plan’s disk limit before you upload media.
- Back up through File Manager. Download the database file and the uploads folder regularly. Restores need the process stopped, as the docs say.
When to move:
If the app goes idle, your scheduled posts do not run, or the build fails, move the site to a Cloud VPS (Path 3). Shared hosting is a reasonable place to test EmDash. Production with scheduled posts needs a process that stays up.
Path 3: Linux Server Without a Panel
Use this path on a VPS or dedicated server with root or sudo access and no control panel, such as a fresh Ubuntu, Debian, AlmaLinux or Rocky Linux server. The commands below come from the EmDash Node.js guide. The process-manager step is general Linux practice, not part of EmDash’s docs.
- Install Node.js 22.16 or later. Use your distribution’s packages or a Node.js version manager. Confirm with
node --version. - Copy the project to the server. Use git, scp or sftp. Work in a directory your app user owns, for example
/var/www/emdash. - Install and build. Run
npm ciand thennpm run build, withEMDASH_SITE_URLset in the environment first. - Set the environment. Put EMDASH_ENCRYPTION_KEY, EMDASH_SITE_URL, DATABASE_PATH, HOST and PORT in the service environment. The standalone Node entry does not read a .env file.
- Start the server. Run
node ./dist/server/entry.mjsto test it. Then keep it running with a service manager. - Put a proxy in front. Use Nginx, Caddy or your panel’s proxy to serve HTTPS on your domain and forward to the EmDash port. Set EMDASH_SITE_URL to the public HTTPS address.
Keeping the Process Running
EmDash’s docs say scheduled tasks run inside the Node process, so the process must stay up. On a server with systemd, a service file keeps it running and restarts it after a crash or reboot. The example below is general systemd practice and has not been tested with EmDash. Replace the paths and user with yours, and test it on a staging server first.
[Unit]
Description=EmDash CMS
After=network.target
[Service]
User=emdash
WorkingDirectory=/var/www/emdash
EnvironmentFile=/etc/emdash/emdash.env
ExecStart=/usr/bin/node ./dist/server/entry.mjs
Restart=always
[Install]
WantedBy=multi-user.target
Docker is also documented by EmDash. The docs include a Dockerfile that builds on node:22-alpine and a Compose file with a named volume for /app/data. Use it on a server where Docker is already set up.
Checks Before You Send Traffic
These checks come from EmDash’s docs, which say to keep a new instance out of traffic until every applicable check passes. The migration check needs a terminal, so run it on your computer or a server with SSH. On shared hosting without SSH, the first request applies migrations automatically, and the admin test shows whether it worked.
- Request /health and one public page. Both must return a successful response. Create the health route before the build, at
src/pages/health.ts, returning OK with status 200. - Run the migration check from the built project with
npx emdash migrate --check, if you have a terminal. It must report no pending or unknown migrations. - Sign in to /_emdash/admin/, create a disposable draft, publish it and confirm the public page changes.
- Upload a test media file, open its URL, then delete it.
- Test a scheduled post if you rely on scheduled publishing, and confirm it goes live.
- Check sandboxed plugins, if you use them. Invoke one plugin route and confirm the log has no sandbox or startup error.
The health route only proves that the Node process can serve pages. It does not prove that the database, storage or plugin sandbox is healthy, so run the other checks as well.
Backups
EmDash’s docs say to back up both the SQLite file and the upload directory, and to stop the process before replacing either during recovery. Keep a copy of EMDASH_ENCRYPTION_KEY separately, because the docs say that restoring a database without the key leaves plugin secrets unreadable.
- Shared hosting and panels: download the database file and uploads folder from File Manager on a schedule.
- Servers: copy the database and uploads with your normal backup tools, and keep at least one copy off the server.
- Restore: stop the process, replace the files, then start it again and run the checks.
Updating EmDash
EmDash’s update guide says to update the emdash and @emdash-cms/cloudflare packages in one step, because they share a version and the Cloudflare package depends on the exact matching version. Plugin packages have their own versions and declare the minimum EmDash version they need. Back up before any update.
- Read the release notes. A major release can require changes to your project.
- Update, build and restart. Update the package, run the build again with EMDASH_SITE_URL set, then restart the app.
- Check the site. Run the checks above again before you send traffic.
- Template files do not update automatically. Compare your layouts and configuration with the current template yourself.
Errors and Fixes
The table lists errors that EmDash’s docs describe. We have not found documented fixes for cPanel-specific errors, so those are marked as not documented.
| Symptom | Where | Fix from the docs |
|---|---|---|
| ExperimentalWarning: SQLite | Node 22 | Expected. It does not stop the database from opening. |
| Plugin secrets cannot be saved or read | Any Node install | Check EMDASH_ENCRYPTION_KEY is set and valid. Generate one with npx emdash secrets generate. |
| Images are not optimised | Build | Set EMDASH_SITE_URL before npm run build. |
| Scheduled posts do not publish | Any Node install | Keep at least one Node process running. The scheduler pauses when no process runs. |
| D1 or R2 binding not found | Cloudflare | Check the binding names in wrangler.jsonc match the EmDash configuration (DB and MEDIA in the template). |
| Migration or schema errors | Cloudflare | Run wrangler tail and reproduce the error to capture the logs. |
| App does not start on cPanel | cPanel app manager | Not documented by EmDash. Check the startup file path, Node version and the app log in the app manager. Ask UnderHost support if the log is unclear. |
| Build fails on shared hosting | cPanel shared | Not documented by EmDash. Build on your computer, then upload dist/. |
Alternative: Cloudflare Workers
If you do not want to run a server, EmDash documents a Cloudflare route with Workers, D1 for the database and R2 for media. You log in with Wrangler on your computer, build, and deploy. The site then runs on Cloudflare, not on your hosting account.
- Run
pnpm wrangler login, thenpnpm build, thenpnpm wrangler deploy. The first deploy creates the D1 database and R2 bucket. - The template includes a Cron Trigger for scheduled publishing and maintenance.
- Point your domain to the Worker in Cloudflare, and set SSL in your Cloudflare zone.
Use the Cloudflare route when you want no server to manage. Keep your hosting account for other sites, and remember that the EmDash site and its data then live on Cloudflare.
Need a Server That Keeps EmDash Running?
A Cloud VPS gives you Node.js 22.16 or later, a process that stays up, and root access for backups and updates. Start with a test site, then move production when the checks pass.
View Cloud VPS PlansCompare Shared HostingAsk @CustomerPanel
Frequently Asked Questions
Can I install EmDash on cPanel?
Yes, if the cPanel account has Node.js 22.16 or later and a Setup Node.js App tool. Use the cPanel path in this guide. Confirm the Node.js version first, because EmDash will not run on an older version.
Do I need SSH to install EmDash?
No, not for the cPanel path. The app manager runs the server, and environment variables are set in cPanel. You do need a way to run the build: either the app manager’s install step, or building on your own computer and uploading the output. SSH makes the build and the checks easier on a server without a panel.
Can I install EmDash on UnderHost shared hosting?
Yes, using the cPanel Node.js app path, on a plan with Node.js 22.16+. Shared hosting has memory and process limits, and a process that goes idle can pause scheduled publishing. Use a Cloud VPS for a production site with scheduled posts.
What Node.js version does EmDash need?
Node.js 22.16.0 or later, as stated in the EmDash deployment docs and the package engines field. Node 22 prints an ExperimentalWarning about SQLite. The docs say the warning does not stop the database from opening.
How do I create the admin account?
Open /_emdash/admin/ on your site. A new site redirects to the setup wizard. Enter a site title and your email, then register a passkey in the browser. The setup wizard runs once.
Where is my content stored?
On a Node.js install with SQLite, content is in the database file set by DATABASE_PATH or the config, and uploads are in the upload directory. Back up both, and stop the process before restoring either.
What if scheduled posts do not publish?
EmDash’s docs say the scheduler runs only while a Node.js process is running, and pauses when every process stops or sleeps. Keep at least one process running in production. On shared hosting, test a scheduled post to see whether the app stays up.
Can I install EmDash on Cloudflare instead?
Yes. Cloudflare Workers with D1 and R2 is a documented route that needs no server shell, because you deploy with Wrangler from your own computer. The site then runs on Cloudflare, not on your cPanel account.
