Ahosting Logo
Knowledge Base

Running Node.js and Python Applications in cPanel

PHP and a Node or Python application deploy in opposite waysPHPNode or PythonHow it runsa file is executed per requestone long-running processAfter changing a filethe next request uses itnothing changes until you restartState between requestsnonekept in the processWhat you mustconfigurealmost nothingthe virtual environment and the assignedportMost "my change did not take effect" reports on a Node app are a process that was never restarted.

cPanel can run Node.js, Python and Ruby applications alongside PHP. The interface is called Application Manager or, on some servers, the individual "Setup Node.js App" and "Setup Python App" tools.

What it gives you is a persistent process with its own dependencies, proxied to your domain, without root, and without managing a server.

How it differs from PHP

Worth understanding first, because it changes how deployment works.

PHP runs per request: a file is executed, output is returned, nothing persists. Upload a changed file and the next request uses it.

A Node or Python application is a long-running process. It starts once and stays in memory. Changing a file does nothing until the application is restarted, and that catches people out repeatedly. The code is correct, the site serves the old version.

Setting one up

In cPanel, open the relevant setup tool and create an application.

Application root, where your code lives, relative to your home directory. Put it outside public_html. Files inside the public directory can be downloaded directly, and that includes configuration holding credentials.

Application URL. The domain or path visitors use. cPanel sets up the proxying.

Startup file. The entry point, such as app.js.

Version; the runtime version. Choose deliberately; changing it later means reinstalling dependencies.

The virtual environment

Creating an application creates an isolated environment holding its own dependencies. That is what stops two applications needing conflicting versions of the same library from interfering.

It also means you cannot install packages from an ordinary terminal session. Commands run outside the environment install into the wrong place, or fail, and the error is not always clear about why.

The setup screen shows a command to enter the environment. Run that first, every time, before installing anything.

Installing dependencies

Put your requirements in the standard file (package.json for Node, requirements.txt for Python) and use the button on the application's screen to install them.

Doing it through the interface guarantees it happens inside the right environment. Doing it by hand works too, once you are in the environment.

Commit those files to your repository. An application whose dependencies exist only on the server cannot be redeployed reliably.

The port is assigned, not chosen

Your application must listen on the port cPanel gives it, exposed as an environment variable:

const port = process.env.PORT || 3000;

Hardcoding a port is the most common reason an application starts and the URL returns an error. The process is running; nothing is proxied to it.

The same applies to the host. Bind to what the environment provides rather than choosing an interface yourself.

Environment variables for configuration

The application screen has a section for environment variables. Use it for database credentials, API keys and anything else that differs between environments.

This is materially better than a configuration file in the application directory: the values are not in your repository, and they are not in a file that could be served if the application root is ever misplaced.

Restart after every change

The button is on the application's screen. Nothing you upload takes effect until you press it.

If a restart does not seem to apply the change, check that you edited the file the startup path actually points at. A second copy of the project in the home directory is a surprisingly common cause of an hour lost.

Resource limits still apply

A persistent process holds memory continuously, unlike PHP which releases it after each request. On a shared plan that counts against the same allowance.

An application with a memory leak grows until it hits the ceiling and is killed, which appears as an application that works for a few days and then stops. Restarting fixes it temporarily and the pattern repeats.

Watch usage instead of waiting for the symptom. Monitoring your hosting resources deals with where to look.

When it will not start

The application's own log is the place to look, and cPanel shows its location on the setup screen.

Four causes cover most failures. A missing dependency, because install ran outside the environment. A hardcoded port. A wrong startup file path. A syntax error that never reached testing.

Run the startup file manually from inside the environment to see the error directly. That is far faster than reading a proxy error, which only tells you nothing answered. There is more on getting a shell in cPanel terminal and SSH access.

When to move to a VPS instead

Shared hosting suits a modest application with steady memory use.

Move when you need a runtime version the server does not offer, a background worker or queue, more memory than the plan allows, or control over how the process is supervised.

On a VPS you run the process yourself behind a proxy, which is more work and removes every ceiling. Setting up Nginx as a reverse proxy sets out that arrangement.

Read the application log, not the web server log

An application running as its own process writes its errors somewhere the usual log does not cover.

ls -la ~/logs/ 2>/dev/null | grep -iE 'node|python|passenger|app'
tail -50 ~/logs/passenger.log 2>/dev/null
tail -50 ~/nodevenv/app/*/error.log 2>/dev/null

A page returning a server error with nothing in the web server log means the application failed and the log to read is its own.

The message there is usually specific: a missing module, a port already in use, a file it cannot read, or a syntax error in a file that was edited last. Each is a direct fix, and none of them is visible from the interface that reports the application as stopped.

The environment is not your shell

An application started by the panel runs with a different environment from the one you get when you connect, and that difference explains most of the failures that make no sense.

which node python3; node -v 2>/dev/null; python3 -V
source ~/nodevenv/app/18/bin/activate 2>/dev/null && node -v
env | grep -iE 'path|node|python' | head

Activating the environment before testing is what makes the shell match what the application actually runs with. Testing outside it uses whatever version the system provides, which is frequently older and has none of the installed packages.

The same applies to anything scheduled. A job that calls the interpreter by name gets the system one, and the fix is to call the specific path inside the environment.

Confirm it comes back on its own

An application started by hand runs until something stops it, and nothing restarts it.

curl -s -o /dev/null -w '%{http_code}\n' https://example.com/app/
ps aux | grep -c '[n]ode\|[p]ython3'
ls -la ~/public_html/app/tmp/restart.txt 2>/dev/null

Restart it deliberately and confirm it returns. Then check again the following day, since a process killed overnight for exceeding a memory limit is the common case and it leaves no message anywhere obvious.

Memory is the usual reason. An application that grows steadily will eventually be terminated, and the difference between a site that recovers by itself and one that stays down until somebody notices is whether anything is configured to start it again.