> ## Documentation Index
> Fetch the complete documentation index at: https://help.noxity.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy a Node.js app

> Walk through deploying an existing Node.js project to cPanel: create the container, upload your code, install dependencies, set environment variables, and start the app.

<div className="not-prose mb-8 pb-6 border-b border-gray-200 dark:border-gray-800">
  <div className="mb-3 text-sm text-gray-500 dark:text-gray-400">
    Updated: May 17, 2026
  </div>

  <div className="flex flex-wrap items-center gap-x-5 gap-y-3">
    <div className="flex items-center gap-3">
      <img src="https://mintcdn.com/noxity/7AGDPHJNWXOTggDq/images/team/matic.png?fit=max&auto=format&n=7AGDPHJNWXOTggDq&q=85&s=236856f5898caae2ec034701c8cb2290" alt="Matic Bončina" className="w-10 h-10 rounded-full object-cover" width="256" height="256" data-path="images/team/matic.png" />

      <div className="flex flex-col leading-tight">
        <span className="text-sm text-gray-900 dark:text-gray-100">
          By <strong className="font-semibold">Matic Bončina</strong>
        </span>

        <span className="text-sm text-gray-500 dark:text-gray-400">
          Founder
        </span>
      </div>
    </div>

    <div className="ml-auto">
      <span className="inline-flex items-center gap-1.5 text-[11px] tracking-wide uppercase font-semibold px-2.5 py-1 rounded-full bg-gray-200 text-gray-700 dark:bg-gray-800 dark:text-gray-300">
        <Icon icon="clock" size={14} iconType="regular" />

        Review pending
      </span>
    </div>
  </div>
</div>

This page walks through deploying an existing Node.js project to cPanel: from code on your laptop to a running app at a public URL. For the underlying tool reference, see [Node.js](/web-hosting/virtual-containers/nodejs).

## Before you begin

* A Node.js project on your machine with a `package.json` and an entry file (commonly `app.js` or `server.js`).
* cPanel access on a plan that exposes **Setup Node.js App**.
* A domain or subdomain already pointed at the account.

If your project uses a specific framework, the framework-specific guide is shorter:

<CardGroup cols={2}>
  <Card title="Deploy Express" icon="diagram-project" href="/how-to/virtual-containers/nodejs/express">REST API on Express.</Card>
  <Card title="Deploy Next.js" icon="react" href="/how-to/virtual-containers/nodejs/nextjs">SSR Next.js with a custom server.</Card>
</CardGroup>

## Create the container

<Steps>
  <Step title="Open Setup Node.js App">
    From cPanel home, scroll to **Software** and click **Setup Node.js App**.

    <Frame caption="cPanel home → Software → Setup Node.js App">
      <img src="https://mintlify.s3.us-west-1.amazonaws.com/noxity/images/how-to/virtual-containers/nodejs/deploy/open-setup-light.png" alt="Setup Node.js App icon in the Software row" className="block dark:hidden" />

      <img src="https://mintlify.s3.us-west-1.amazonaws.com/noxity/images/how-to/virtual-containers/nodejs/deploy/open-setup-dark.png" alt="Setup Node.js App icon in the Software row" className="hidden dark:block" />
    </Frame>
  </Step>

  <Step title="Click + Create Application">
    On an empty account you land on a list page with a single **+ Create Application** button.

    <Frame caption="Application list with the Create Application button">
      <img src="https://mintlify.s3.us-west-1.amazonaws.com/noxity/images/how-to/virtual-containers/nodejs/deploy/create-application-light.png" alt="Empty Node.js app list with Create Application button" className="block dark:hidden" />

      <img src="https://mintlify.s3.us-west-1.amazonaws.com/noxity/images/how-to/virtual-containers/nodejs/deploy/create-application-dark.png" alt="Empty Node.js app list with Create Application button" className="hidden dark:block" />
    </Frame>
  </Step>

  <Step title="Fill in the form">
    * **Node.js version**: pick the highest LTS your code supports. Most projects want 22 or 20.
    * **Application mode**: `Production`. Switch to Development only while chasing a boot error.
    * **Application root**: a folder under your home directory, e.g. `myapp`. Created for you if it doesn't exist.
    * **Application URL**: the domain dropdown plus an optional path. Use `/` for the root or `/api` to mount the app on a sub-path.
    * **Application startup file**: defaults to `app.js`. Set this to the file that exports your handler.
    * **Passenger log file**: optional, but worth setting (e.g. `logs/passenger.log`). It's where boot errors land.

    <Frame caption="Create Application form filled in for a sample app">
      <img src="https://mintlify.s3.us-west-1.amazonaws.com/noxity/images/how-to/virtual-containers/nodejs/deploy/create-form-light.png" alt="Create Application form" className="block dark:hidden" />

      <img src="https://mintlify.s3.us-west-1.amazonaws.com/noxity/images/how-to/virtual-containers/nodejs/deploy/create-form-dark.png" alt="Create Application form" className="hidden dark:block" />
    </Frame>
  </Step>

  <Step title="Click Create">
    Passenger starts an empty placeholder app. You'll get a green "running" indicator and a management page.
  </Step>
</Steps>

The full set of buttons on the management page is covered in the [Node.js reference](/web-hosting/virtual-containers/nodejs#manage-an-app).

## Upload your code

Three workflows. Pick whichever fits how your project lives today.

<Tabs>
  <Tab title="File Manager">
    Zip your project locally (skip `node_modules` and `.git`), then:

    1. cPanel home → **File Manager**.
    2. Navigate to the application root you created (e.g. `~/myapp`).
    3. **Upload** the zip, then right-click it and **Extract** in place.
    4. Delete the zip once the contents are extracted.
  </Tab>

  <Tab title="SFTP">
    Connect with FileZilla, Cyberduck, or VS Code's SFTP extension. Credentials are your cPanel username and password, port 22.

    Sync your project into `~/myapp/`. Exclude `node_modules` and `.git` from the transfer. `node_modules` is rebuilt on the server against the per-app Node env, and `.git` adds noise without value.
  </Tab>

  <Tab title="Git">
    For a git-tracked project, use cPanel's **Git Version Control** tool:

    1. cPanel home → **Files** → **Git Version Control**.
    2. **Create** → paste your repo URL, set **Repository Path** to your application root (e.g. `/home/<user>/myapp`).
    3. cPanel clones the repo into that directory.

    For subsequent updates, run `git pull` over SSH then hit **Restart** on the Node.js app page. See [Git Version Control](/web-hosting/cpanel/file-management/git-version-control) for the full flow.
  </Tab>
</Tabs>

## Install dependencies

Back on **Setup Node.js App**, find your app in the list and open it. Click **Run NPM Install**. cPanel sources the per-app virtualenv, then runs `npm install` against the `package.json` in your application root.

Big dependency trees (Next.js, Nuxt, Strapi, anything that pulls in `sharp`) can OOM during install. Run it over SSH instead, with flags that keep the resident set smaller:

```bash theme={}
source ~/nodevenv/myapp/22/bin/activate && cd ~/myapp
npm install --prefer-offline --no-audit
```

PMEM on a shared plan caps around 1 GB. If you keep hitting it, build `node_modules` on a dev machine and rsync the tree up.

## Set environment variables

The **Environment variables** editor sits below the buttons on the management page. Add entries one at a time. Variable names take letters, numbers, underscores, and dashes (max 256 characters). Values are ASCII, max 1024 characters.

Common ones to set:

| Name           | Example value                        | Why                                                       |
| -------------- | ------------------------------------ | --------------------------------------------------------- |
| `NODE_ENV`     | `production`                         | Many libraries flip into a faster code path on this flag. |
| `DATABASE_URL` | `mysql://user:pass@localhost/dbname` | Don't commit secrets to git. Read them from env.          |
| `JWT_SECRET`   | 32+ random characters                | Same. Rotate from here, not from the code.                |

<Note>
  Don't set `PORT`. Passenger ignores it. It drives the runtime over a Unix socket, not a TCP port. If your code reads `process.env.PORT`, that's fine, but the value is irrelevant.
</Note>

Click **Save** under the editor, then **Restart** for the changes to take effect.

## Make the entry file Passenger-compatible

Passenger runs your code. **Your code does not start an HTTP server.** Export an `http.Server` or an Express app, do not call `.listen()`.

```js app.js theme={}
const express = require('express');
const app = express();

app.get('/', (_req, res) => res.send('Hello from Passenger'));

module.exports = app;
```

For a plain HTTP server with no framework:

```js app.js theme={}
const http = require('http');

module.exports = http.createServer((req, res) => {
  res.end('Hello from Passenger\n');
});
```

<Warning>
  Calling `app.listen(PORT)` from a Passenger-managed app produces a 503 on every request, with an `EADDRINUSE` or boot error in the Passenger log. Tutorials written for VPS deployment have this line. Delete it.
</Warning>

If your project shipped with a `listen()` call, edit the file in place (File Manager → right-click → **Edit**, or via SSH) before the next restart.

## Start and verify

<Steps>
  <Step title="Restart from the management page">
    Click **Restart**. Equivalent to `touch ~/myapp/tmp/restart.txt` from SSH.
  </Step>

  <Step title="Hit the URL">
    Open the **Application URL** in a browser. Your app should respond.
  </Step>

  <Step title="If it's a 503, check the log">
    The Passenger log file you set when creating the app holds the boot trace. From SSH:

    ```bash theme={}
    tail -n 100 ~/myapp/logs/passenger.log
    ```
  </Step>
</Steps>

## Common issues

<AccordionGroup>
  <Accordion title="503 on every request">
    Almost always `app.listen(PORT)` in the startup file. Swap to `module.exports = app`, then **Restart**.
  </Accordion>

  <Accordion title="Cannot find module 'X' after deploying">
    `package.json` is in the right place, but `node_modules` was built on a different machine or Node version. Click **Run NPM Install** so it builds against the per-app env.
  </Accordion>

  <Accordion title="Boot times out after 60 seconds">
    Passenger's default startup window. If your app loads a large dataset or runs a synchronous DNS lookup on boot, raise the cap. Edit `~/myapp/.htaccess` and add above the Selector-managed block:

    ```apache theme={}
    PassengerStartTimeout 120
    ```
  </Accordion>

  <Accordion title="App URL returns the cPanel default page, not your app">
    The application URL is set to a sub-path (`/api`) but you're hitting `/`. Either change the URL in the form, or move your routes so they match the configured path.
  </Accordion>

  <Accordion title="`npm install` runs out of memory">
    PMEM is \~1 GB on shared plans. Run install over SSH with `--prefer-offline --no-audit`, or build `node_modules` locally and rsync the directory up.
  </Accordion>

  <Accordion title="Env var change doesn't take effect">
    Saving the editor stores the value but doesn't reload the process. Hit **Restart** after every change.
  </Accordion>
</AccordionGroup>

## Next

<CardGroup cols={2}>
  <Card title="Deploy Express" icon="diagram-project" href="/how-to/virtual-containers/nodejs/express">Wire up an Express API.</Card>
  <Card title="Deploy Next.js" icon="react" href="/how-to/virtual-containers/nodejs/nextjs">Run SSR Next.js behind Passenger.</Card>
</CardGroup>

## Need a hand?

<CardGroup cols={2}>
  <Card title="Open a ticket" icon="life-ring" href="https://members.noxity.io/submitticket.php">
    Best for anything that needs an account check or a config change on our end.
  </Card>

  <Card title="Live chat" icon="messages" href="https://noxity.io/contact">
    Faster for quick questions during business hours.
  </Card>
</CardGroup>

<div className="mt-8">
  <Accordion title="Sources" icon="book-bookmark">
    * [Node.js reference](/web-hosting/virtual-containers/nodejs)
    * [Virtual Containers overview](/web-hosting/virtual-containers/overview)
    * [Git Version Control](/web-hosting/cpanel/file-management/git-version-control)
    * [Setup Node.js App ↗](https://docs.cpanel.net/cpanel/software/setup-nodejs-app/)
    * [CloudLinux Node.js Selector ↗](https://docs.cloudlinux.com/cloudlinuxos/cloudlinux_os_components/#nodejs-selector)
    * [Phusion Passenger Node.js walkthrough ↗](https://www.phusionpassenger.com/library/walkthroughs/start/nodejs.html)
    * [How to deploy a Node.js app with cPanel ↗](https://www.thecpaneladmin.com/how-to-deploy-a-node-js-app-with-cpanel/)
  </Accordion>
</div>
