Bütün yazılarTUTORIAL · 7 DƏQ OXUMA

Deploy your Node.js app on Rivervo hosting (Next.js & Nuxt).

TL
Tomas Linnamäki · Platform Engineer
·
April 29, 2026
Node
ON SHARED HOSTING

People assume Node.js apps have to live on a VPS. They don't — every Rivervo shared hosting plan has the Setup Node.js App tool in cPanel, which spins up a Phusion Passenger process for your app behind the same Apache front-end that serves your other sites.

This guide walks through the whole flow for the two frameworks 90% of customers ask about: Next.js and Nuxt 3. The end state: your app at https://yourdomain.com (or any subdomain), running on a real Node.js process, surviving reboots, restartable with one click.

If you've never deployed a Node app to cPanel before, the part everyone gets stuck on is the startup file — Passenger needs a single entry script that boots your framework. We'll provide one for each framework below; copy-paste, no edits required.

What you need before starting

  • A Rivervo hosting plan (any tier — Node.js Selector is enabled on all plans)
  • Node.js v20 or newer locally to build your app
  • The built artefact, ready to upload (we'll cover this per framework)
  • File Manager or SFTP access to your account (both work)

You do not need root, sudo, systemd, or a reverse-proxy config. Passenger handles all of that.

Step 1 — Build your app locally

You're going to upload a built app, not the source. cPanel will install dependencies but it won't compile React or run a Vite build. Do that on your machine first.

Next.js:

npm ci
npm run build

That produces .next/ (the built output). Don't next start here — we'll launch it from the startup file in a minute.

Nuxt 3:

npm ci
npm run build

That produces .output/ (Nuxt's universal build directory). Same deal — don't run anything yet.

Step 2 — Upload the right files

You don't need to upload node_modules/. cPanel's Node.js Selector installs dependencies for you. You also don't need git or build caches.

Upload to your account, ideally to a path outside public_html (e.g. /home/<account>/myapp/). Why outside? Because Passenger will mount public_html at the URL root automatically, and putting your app code in there exposes it.

FrameworkUpload theseSkip
Next.js.next/, public/, package.json, package-lock.json, next.config.js, your server.cjs (below)node_modules/, .git/, .env.local
Nuxt 3.output/, package.json, package-lock.json, your server.cjs (below)node_modules/, .nuxt/, .git/, source pages/, components/

Two ways to get files there:

  • File Manager → Upload → drag and drop a zip → "Extract" is the easiest if you have a flaky connection.
  • SFTP (FileZilla, Cyberduck, rsync) is faster for repeat deployments. Port 22, your cPanel username, your cPanel password.

Step 3 — Add the startup file

This is the file Passenger executes when a request comes in. Drop it next to package.json in your app folder.

For Next.js — server.cjs

const next = require('next')
const http = require('http')
 
const port = process.env.PORT || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev, dir: __dirname })
const handle = app.getRequestHandler()
 
app.prepare().then(() => {
  http.createServer((req, res) => handle(req, res)).listen(port, () => {
    console.log(`Next.js server listening on port ${port}`)
  })
})

What it does:

  • Loads Next, points it at the current directory (where your .next/ and package.json live).
  • Builds a request handler from Next's internal router.
  • Starts an HTTP server on the port Passenger assigns (process.env.PORT).
  • Falls back to 3000 for local testing.

dev is auto-derived from NODE_ENV — set NODE_ENV=production in cPanel (we'll do that in Step 4) and Next runs in production mode.

For Nuxt 3 — server.cjs

import('./.output/server/index.mjs').then(({ createApp }) => {
  createApp().then(({ app }) => {
    const port = process.env.PORT || 3000
    app.listen(port, () => {
      console.log(`Nuxt server listening on port ${port}`)
    })
  })
})

What it does:

  • Dynamically imports Nuxt's .output/server/index.mjs (the entry produced by npm run build).
  • Uses createApp() to build the H3 server instance.
  • Listens on Passenger's assigned port.

The dynamic import() is intentional — .mjs modules can't be require()'d, but a .cjs file can dynamically import them. This is the cleanest pattern that works inside cPanel's launcher.

Step 4 — Configure Node.js Selector

Open cPanel → Setup Node.js AppCreate Application.

FieldValue
Node.js version20.x or newer
Application modeProduction
Application root/home/<account>/myapp (where you uploaded the files)
Application URLyourdomain.com (or a subdomain like app.yourdomain.com)
Application startup fileserver.cjs

Click Create. cPanel generates a virtual environment under ~/nodevenv/myapp/20/.

Install dependencies

Once the app is created, scroll down to Detected configuration files — you should see your package.json. Click Run NPM Install and watch the log. If it fails:

  • Check that package.json is at the application root (not nested).
  • For Next.js: confirm next is in dependencies, not devDependencies (production install skips dev deps).
  • For Nuxt: nuxt itself should also be a regular dependency.

Add environment variables

Same screen, Environment variables section. At minimum:

NODE_ENV=production

For Next.js apps that read at runtime (database URLs, API keys), add them here. Don't ship a .env file with secrets — cPanel's env vars are the right place.

Click Restart after adding any env var. Without a restart, the running process keeps the old environment.

Step 5 — Verify

Visit your application URL. You should see your app.

If you see a Passenger error page, expand it and look at the bottom — there's almost always a clear stack trace. The two most common:

Error: Cannot find module 'next'npm install didn't run, or it ran in the wrong folder. Re-run NPM Install from cPanel.

Error: ENOENT: no such file or directory, open '.next/...' — you uploaded the source but not the built .next/ directory. Build locally and re-upload.

How to deploy updates

Repeat steps 1, 2, and the Restart click in Node.js Selector. Specifically:

1. Build locally    npm run build
2. Upload          .next/ or .output/, plus any changed source/config
3. cPanel          Restart application

If you change package.json, re-run Run NPM Install before restarting.

Common gotchas

WebSockets: cPanel's Passenger handles HTTP/1.1 and HTTP/2. WebSocket upgrade works for Next.js and Nuxt's built-in routes. If you're using a separate WebSocket server (ws, socket.io), it shares the same port and starts via the same server.cjs — no extra config.

File uploads / next.config.js body-parser limits: Passenger's default request body limit is 10 MB. If you're uploading large files, set passenger_max_request_size higher via .htaccess in public_html:

PassengerMaxRequestSize 52428800

(50 MB in bytes.)

Cron jobs: if your app needs background tasks (newsletter sends, scheduled exports), don't run them inside the web process. Use cPanel's Cron Jobs to invoke a Node script directly:

/home/<account>/nodevenv/myapp/20/bin/node /home/<account>/myapp/scripts/send-newsletter.js

Process memory: Passenger restarts your app if it exceeds the per-account RAM cap (depends on your plan). For a typical Next.js / Nuxt app, idle is under 100 MB. If you're hitting limits, profile with process.memoryUsage() and look for leaks before assuming you need a bigger plan.

Custom domains and HTTPS: the app URL you set in Node.js Selector is what Passenger binds. SSL is automatic via AutoSSL — no extra config. If you want a wildcard or a custom domain pointing at a subdirectory, set up the domain in Domains first, then in Node.js Selector.

Outdated Node version: if your app needs Node 22 or 23, open a ticket. We have multiple versions available; the dropdown shows what's installed for your plan.

When not to use shared hosting for Node

To be straightforward — shared hosting Node.js works great for portfolio sites, blogs, marketing pages, small SaaS frontends, internal tools. It struggles for:

  • High-throughput APIs (>50 req/sec sustained) — you'll feel the per-account CPU cap
  • WebSocket-heavy apps with thousands of concurrent connections
  • Apps that fork worker processes (queue workers, scrapers) — Passenger's per-account process budget makes this awkward
  • Anything needing systemd, Docker, or root access

For those, our VPS is the right move — full root, your own kernel, runs whatever you want. But for most Next.js and Nuxt apps that aren't fielding huge traffic, this guide is all you need.

TL;DR

  1. npm run build locally
  2. Upload .next/ (Next) or .output/ (Nuxt) + package.json + server.cjs
  3. cPanel → Setup Node.js App → point at the folder, set startup file to server.cjs
  4. Run NPM Install, set NODE_ENV=production, Restart

If anything misbehaves, open a ticket — paste the Passenger error page and we'll point at the line.

— Tomas