Deploy Node.js on Shared Hosting with Phusion Passenger

Node.js isn't exclusive to VPS servers. Modern shared hosting — including DirectAdmin-based setups — supports running Node.js apps via Phusion Passenger, an application server that bridges Apache or Nginx with your Node.js app. This guide walks you through deploying a Node.js app on shared hosting step by step.

What is Phusion Passenger?

Phusion Passenger is a multi-language application server supporting Ruby, Python, and Node.js. It acts as middleware between the web server (Apache/Nginx) and your app. When an HTTP request arrives, Passenger forwards it to a Node.js process and returns the response — eliminating the need to configure a reverse proxy manually.

Check Node.js Availability on Your Hosting

Before deploying, verify that your hosting supports Node.js by SSHing in and running:

node --version npm --version which node

Note: Node.js on shared hosting has more limitations than VPS, as resources are shared. For apps that need to run continuously or handle high traffic, a VPS starting at 500 THB/month provides full control with PM2 and unrestricted Node.js.

Folder Structure for Node.js on Passenger

public_html/ ├── app.js ← Main app entry point ├── package.json ├── node_modules/ └── public/ ← Static files └── .htaccess ← Passenger configuration

Step 1: Create app.js

const http = require('http'); const server = http.createServer((req, res) => { res.writeHead(200, {'Content-Type': 'text/html'}); res.end('<h1>Node.js on Shared Hosting Works!</h1>'); }); if (typeof(PhusionPassenger) !== 'undefined') { PhusionPassenger.configure({ autoInstall: false }); server.listen('passenger'); } else { server.listen(3000, () => { console.log('Server running on port 3000'); }); }

Step 2: Create package.json

{ "name": "my-nodejs-app", "version": "1.0.0", "main": "app.js", "scripts": { "start": "node app.js" } }

Step 3: Configure .htaccess

PassengerEnabled on PassengerAppRoot /home/username/public_html PassengerAppType node PassengerStartupFile app.js <Directory /home/username/public_html> Allow from all </Directory>

Replace username with your DirectAdmin username.

Step 4: Install Dependencies

cd ~/public_html npm install

Step 5: Restart Passenger

After modifying your app, restart Passenger by touching the restart file:

mkdir -p tmp touch tmp/restart.txt

Express.js on Passenger

const express = require('express'); const app = express(); app.get('/', (req, res) => { res.send('Hello from Express on Shared Hosting!'); }); if (typeof(PhusionPassenger) !== 'undefined') { PhusionPassenger.configure({ autoInstall: false }); app.listen('passenger'); } else { app.listen(3000); }

Deploy via the Node.js Selector on DirectAdmin (No Manual .htaccess)

Many modern DirectAdmin servers ship with a Node.js Selector (CloudLinux), which lets you create and manage Node.js apps entirely from the control panel UI — no hand-written .htaccess required. This approach is ideal for beginners because every setting is a click away. AsiaGB hosting runs on DirectAdmin, so it supports this workflow.

To create a Node.js app through the DirectAdmin Node.js Selector:

  1. Log in to DirectAdmin and open Extra Features → Setup Node.js App (also called "Node.js Selector").
  2. Click CREATE APPLICATION to start a new app.
  3. Pick the Node.js version from the dropdown (e.g. 18.x or 20.x LTS).
  4. Set the Application root, e.g. nodeapp (maps to /home/username/nodeapp).
  5. Set the Application URL — the domain or subdomain the app will serve, such as app.yourdomain.com.
  6. Set the Application startup file to app.js (your entry point).
  7. Click CREATE — the system provisions a virtualenv and configures Passenger automatically.

After creation, DirectAdmin shows a command to enter the virtual environment (e.g. source /home/username/nodevenv/nodeapp/18/bin/activate). Run it before using npm over SSH so you get the correct Node.js version.

Configure the App: Entry Point, Environment Variables, and npm install via the UI

Once the app exists, you can tune everything from the Node.js Selector page without touching the terminal:

Entry Point (Startup File)

The Application startup file field is the file Passenger calls when the app boots — usually app.js. If your project uses a different name such as server.js or index.js, update this field, click Save, then Restart.

Environment Variables

The app page includes an "Add Variable" section to set environment variables like NODE_ENV=production, DB_HOST, or API_KEY — no .env file needed. Values are injected into the process on restart, which is safer than hardcoding secrets in code.

npm install via the UI

The Node.js Selector has a "Run NPM Install" button that reads your package.json and installs all dependencies in the correct environment — no SSH required. This is perfect for hosts that don't expose SSH. To run other scripts defined in package.json, use the "Run JS script" button.

Tip: Whenever you change an environment variable, the entry point, or add a dependency, always click Restart in the Node.js Selector (equivalent to touch tmp/restart.txt). Otherwise the app keeps running the old code.

Shared Hosting vs VPS for Node.js

Running Node.js on shared hosting via Passenger works well for small to medium apps, but there are limits worth understanding before you commit. The table below compares the key differences between shared hosting and a VPS:

Aspect Shared Hosting (Passenger) VPS (PM2)
Process manager None (Passenger, lazy start) Full control via PM2 / systemd
Custom port No (Passenger injects the port) Any port (3000, 8080, etc.)
WebSocket / Socket.io Limited, depends on server config Fully supported
RAM / CPU Shared with others, quota capped Dedicated allocation
Docker / background workers Not supported Fully supported
Best for Small sites, light APIs, demos Production, real-time, high traffic

In short, shared hosting is great for experiments, small APIs, or personal sites with modest traffic. Apps that must run continuously, have background jobs, or use real-time WebSocket should run on a VPS with full root access.

Common Problems and Fixes (502, Ports, Restart)

When you deploy Node.js on shared hosting, most issues trace back to a handful of fixable causes:

1. Error 502 Bad Gateway or Application Error

The most common cause is the app crashing on startup — usually a missing dependency or a syntax error. Check the log first:

cd ~/nodeapp tail -n 50 stderr.log

If you see Cannot find module 'xxx', npm install hasn't run in the correct environment. Click "Run NPM Install" in the Node.js Selector again, or activate the virtualenv before running npm.

2. App Not Listening on the Right Port

On Passenger you must never hardcode a fixed port — let the app listen through Passenger. Make sure your code does this:

const port = process.env.PORT || 3000; app.listen(port);

Passenger sets process.env.PORT for you. A hardcoded app.listen(3000) may work sometimes but is unreliable.

3. Code Changes Not Taking Effect (Restart Required)

Passenger caches the process, so editing files alone has no effect until you restart. Click Restart in the Node.js Selector or run it over SSH:

mkdir -p ~/nodeapp/tmp touch ~/nodeapp/tmp/restart.txt

4. Memory Limit / App Killed

If the app exceeds your hosting plan's RAM quota, the system kills the process, causing intermittent 502s. Check memory usage and trim unnecessary dependencies. If the app genuinely needs more RAM, move it to a VPS with dedicated memory.

Limitations of Node.js on Shared Hosting

Need full Node.js control? AsiaGB VPS starts at 500 THB/month with Full Root Access. Run Node.js with PM2, install Docker, bind any port — perfect for API servers, real-time apps, or microservices. Locations: Thailand and Singapore.

Need Full Node.js Power? Try a VPS

VPS from 500 THB/month. Full Root Access, PM2, Docker, custom ports. Thailand & Singapore locations, 99% Uptime.

View VPS Plans

View all cheap Thailand web hosting plans →