Step-by-step practical guide to host production Next.js apps on cPanel/WHM with Phusion Passenger — covers architecture, prerequisites, build/start scripts, deployment, SSL, and troubleshooting.
! Deploy Next.js on cPanel/WHM with Phusion Passenger
Quick summary
- Use Passenger to run Next.js SSR or a custom server on cPanel/WHM without a separate Node host.
- Choose SSR (next start / custom server) or static export (next export) depending on features and hosting limits.
- Validate Node versions, prepare build/start scripts, set process.env.PORT, and use cPanel’s Node.js manager when available.
Why this approach
This guide shows practical, repeatable steps to run production Next.js on cPanel/WHM using Phusion Passenger. It targets developers with cPanel accounts and host admins running WHM. The goal: get SSR or a production Node server working reliably on shared or managed hosting when Passenger is available.
Architecture overview
- Next.js: can run as SSR (Node server) or as a static export. SSR requires a Node runtime.
- Node.js: executes the Next.js server code.
- Phusion Passenger: spawns and manages Node processes behind Apache or nginx, forwarding HTTP requests.
- cPanel/WHM: controls domains, SSL, and (sometimes) a Node.js app manager that hides Passenger details.
Request flow (typical Apache + Passenger)
- Browser requests https://example.com.
- Apache routes the request to Passenger, which manages the Node process.
- Passenger starts your startup file; your app listens on process.env.PORT.
- Next.js handles rendering and responds via Passenger.
Decide SSR vs static export
- SSR: required for getServerSideProps, server-side APIs, or dynamic per-request rendering.
- Static export: best for fully static sites (no Passenger needed, simplest on shared hosting).
Preparation checklist
- Confirm Passenger is available via cPanel or WHM (ask support if unsure).
- Confirm available Node versions match your Next.js requirements (Node 16/18/20 are common).
- Prefer SSH access for builds and installs; cPanel UI can help but SSH simplifies reproducible deploys.
- If you manage the server, plan to enable Passenger through WHM/EasyApache for a supported install.
Prepare your Next.js app for production
Repository layout (recommended):
- next-app/
- package.json
- server.js <-- startup file for Passenger (SSR)
- next.config.js
- pages/ or app/
- public/
- .env.production
Add clear scripts in package.json so Passenger runs the correct production command. Example package.json snippets:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "NODE_ENV=production node server.js",
"export": "next build && next export"
}
}
A minimal server.js must honor process.env.PORT so Passenger can route requests to the correct socket/port. Example:
const http = require('http');
const next = require('next');
const app = next({ dev: false });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = http.createServer((req, res) => {
handle(req, res);
});
const port = process.env.PORT || 3000;
server.listen(port, (err) => {
if (err) throw err;
console.log(`> Next.js server started on port ${port}`);
});
});
// Optional: Graceful shutdown hooks
process.on('SIGINT', () => process.exit(0));
process.on('SIGTERM', () => process.exit(0));
Notes:
- Use NODE_ENV=production and build with next build before starting.
- For fully static sites, run next export and upload the out/ folder into public_html; no Passenger needed.
- Build locally or on the server. If native modules exist, building on the server avoids binary mismatches.
Enabling Phusion Passenger in WHM
Preferred: use WHM → EasyApache 4 to enable the Passenger Apache module. Steps:
- Log into WHM, open EasyApache 4, Customize, add Passenger (if provided), and provision.
- Restart Apache: sudo systemctl restart httpd
If EasyApache doesn’t provide the module, follow Phusion's official installer (advanced). Avoid mixing manual gem installs with EasyApache-managed modules.
Verify installation (root/WHM):
- Check Apache modules and passenger utilities with passenger-status and passenger-memory-stats.
- Tail Apache logs: see where errors land and confirm Passenger loaded successfully.
Deploy: upload, install deps, build, and run
Common flow (two options: cPanel Node manager or manual Passenger vhost):
1) Prepare start scripts
- Either use next start -p $PORT or a server.js wrapper that listens on process.env.PORT.
- Example start script in package.json: "start": "node server.js" or "next start -p $PORT".
2) Upload your project
- Use Git (recommended), SFTP, or File Manager. Keep the app outside public_html when possible.
3) Install and build on the server (SSH):
- Use package manager commands to install production deps and build the app:
cd ~/next-app
npm ci --only=production --no-audit --progress=false
npm run build
4) Configure the cPanel Node.js App manager (if available)
- Create an app, select Node version, set app root and startup file (server.js or package.json start), add env vars, then Start.
5) Or configure Passenger via vhost include
- Add PassengerAppRoot, PassengerNodejs (optional), and PassengerAppEnv to a vhost include and restart Apache.
6) Start and verify
- cPanel: click Start or Restart.
- Passenger spawns the app on first request (or on start depending on settings). Check logs for errors.
Useful server commands (root or account as allowed):
- Tail webserver logs and Passenger status:
tail -f /usr/local/apache/logs/error_log
passenger-status
passenger-memory-stats
passenger-config restart-app /home/username/path/to/app --ignore-app-not-running
And to follow application logs:
cd ~/path/to/app
tail -f ./npm-debug.log ./next.log ./logs/*.log
Domains, env vars, and SSL
- Map your domain/subdomain to the app root or symlink into the domain DocumentRoot.
- Passenger provides process.env.PORT; your app must respect it.
- Set environment variables via cPanel’s Node.js manager, SetEnv in vhost, or a secure server-side secret store. Avoid committing .env files.
- Use cPanel/WHM AutoSSL to install certificates; Passenger works behind Apache’s SSL termination. Redirect 80 → 443 and add HSTS when appropriate.
Troubleshooting checklist
Common symptoms and fixes:
- 502/503: app failed to start — ensure npm install && npm run build ran and that the startup file listens on process.env.PORT.
- Missing modules: reinstall node_modules on the server (npm ci) and match Node versions.
- Dev server running: ensure you’re not running next dev; use next start or node server.js in production.
- Permissions: set correct owner (chown -R username:username) and file modes (644/755).
Example package.json start scripts for clarity:
"scripts": {
"build": "next build",
"start": "next start -p $PORT"
}
If you cannot access required logs on a shared host, include log excerpts and steps taken when contacting support.
Case study: shared cPanel deploy (short)
Steps taken:
- Clone or upload a minimal Next.js app to /home/username/nodeapps/my-next-app:
git clone https://github.com/vercel/next.js.git
cd next.js/examples/basic-css
npm install
npm run build
- Build on the server:
npm ci
npm run build
- Configure cPanel Node manager to use server.js or next start -p $PORT and start the app.
- Example custom server (Express + Next) can be used if needed:
// server.js
const express = require('express')
const next = require('next')
const dev = false
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
server.get('*', (req, res) => handle(req, res))
const port = parseInt(process.env.PORT, 10) || 3000
server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
})
Common fixes discovered: avoid dev server, rebuild native modules on the server, fix file ownership and permissions.
Conclusion
Running Next.js on cPanel/WHM with Phusion Passenger is a practical option for smaller SSR apps when Passenger is available. Validate Node versions, prepare a production build, use a startup script that honors process.env.PORT, and prefer building on the server when native modules exist. For larger scale, consider migrating to a platform designed for Node.js scaling.
Call to action
Try the steps above on a staging subdomain first. If you need help adapting a project or automating deployment, reach out for assistance.
Home: https://prateeksha.com
Blog: https://prateeksha.com/blog
Canonical: https://prateeksha.com/blog/deploy-nextjs-cpanel-phusion-passenger

Top comments (0)