There are two ways to run a NodeJS application on Ultra Web Hosting, and which one you use depends on your plan. On a managed cPanel account you run Node through cPanel's Setup Node.js App, which serves it for you, and we handle anything that needs server-level access. On a VPS or dedicated server with root, you run Node yourself as a long-lived service under systemd, behind your own nginx and TLS. This guide covers both paths: when each one fits, and the full steps for a persistent, self-managed Node service on a root server.
- Which Path Is Yours
- Managed cPanel: Run Node with Setup Node.js App
- Connect over SSH
- Root Server: Install NodeJS
- Root Server: Create a Service Account and Your App
- Root Server: Keep the App Alive with systemd
- Store Secrets Safely
- Root Server: nginx and HTTPS in Front
- Root Server: Open the Firewall
- Verify, Deploy, and Where to Go Next
Two Paths, Picked by Your Plan
Most Node apps, including websites, APIs, dashboards, and request-driven connectors, run on a managed cPanel account with no root needed. A truly persistent, always-resident process needs a root VPS or dedicated server.
- Managed cPanel: cPanel Setup Node.js App runs it, we configure any server-level pieces
- Root VPS or dedicated: you run Node under systemd behind your own nginx and TLS
- Both serve over HTTPS and keep secrets out of your code
- You never need root for the managed path; we do the privileged parts for you
You Do Not Have to Manage a Server
On a managed cPanel account you get a jailed SSH login to your own files and cPanel to run the app. Anything that needs root, such as a reverse-proxy tweak or a firewall change, we handle for you from a support ticket. You keep a clean, safe account with none of the server upkeep.
- Jailed SSH key to your home directory, no root exposure
- cPanel Setup Node.js App starts, stops, and serves the app
- We own the operating system, updates, and server-level config
01. Which Path Is Yours
Before you start, decide which model fits. The difference is whether you have root on the server.
cPanel Runs It for You
Your shared or cPanel VPS account runs Node through Setup Node.js App. You supply the code; cPanel and Passenger serve it. We handle anything at the server level.
- No root, no systemd, no server to maintain
- Great for sites, APIs, dashboards, and request-driven connectors
- We configure reverse-proxy and firewall needs on request
You Run the Process
You own the box and run Node as a persistent daemon under systemd, behind your own nginx and TLS, with full control of the firewall.
- A persistent process that stays resident between requests
- Needed for background workers and long-lived connections
- You own the OS, updates, and all server config
If you are weighing which plan to be on, article #481 compares shared, VPS, and dedicated hosting. Sections 02 and 03 cover the managed path and SSH; Sections 04 onward are the root-server steps.
02. Managed cPanel: Run Node with Setup Node.js App
On a managed cPanel account you do not start a Node process or run a reverse proxy yourself. cPanel's Setup Node.js App builds the environment and Phusion Passenger serves the app for you. This is the right path for most projects, and it is how we set Node up for managed clients.
- In cPanel, open Setup Node.js App (under Software) and click Create Application.
- Choose your Node version, an application root (the folder your code lives in), and the application URL.
- Set the startup file (for example
server.js), then click Create. - Install dependencies with Run NPM Install, add any environment variables in the panel, and click Restart.
Article #487 walks through this in full. Keep in mind that Passenger loads your app on demand rather than keeping a resident process, so it suits request-and-response work rather than always-on background daemons.
If your app needs something that a jailed account cannot set, such as turning off reverse-proxy buffering for a streaming endpoint, allowing a specific outbound connection, or a custom SSL arrangement, open a support ticket and we will configure it on the server for you. You never need root for this.
The remaining sections of this guide are for the root VPS or dedicated path. If you are on a managed cPanel account, you can stop here and use Setup Node.js App as above.
03. Connect over SSH
Both paths use SSH, and the way you generate and use a key is the same. What differs is the account you log in as. Your server hostname and SSH port are in the email we send when SSH access is set up on your account. Key-based login is more secure than a password and is preferred. Article #60 covers SSH access and keys in more detail.
- Managed cPanel account: you log in as your cPanel user into a jailed shell that is confined to your own files. You request access and send us your public key, and we authorize it for your account.
- Root VPS or dedicated: you log in as root and authorize your own key.
- On your own computer, generate a key pair if you do not already have one. Set a passphrase when prompted:
This writesssh-keygen -t ed25519 -C "[email protected]"~/.ssh/id_ed25519(private) and~/.ssh/id_ed25519.pub(public). - Connect using the username, hostname, and port from your email. For a cPanel account:
For a root server, log in asssh -p PORT -i ~/.ssh/id_ed25519 [email protected]rootand append your public key to/root/.ssh/authorized_keysyourself first.
If the server still asks for a password after a key is in place, the cause is almost always permissions. The .ssh directory must be mode 700 and authorized_keys must be 600 and owned by the login user. A file left owned by the wrong user, or group-writable, makes the SSH daemon ignore the key silently.
04. Root Server: Install NodeJS
The rest of this guide applies to a VPS or dedicated server where you have root. Install a current LTS release of Node. The examples use the RHEL-family dnf package manager, which matches our standard AlmaLinux VPS image. On Debian or Ubuntu, substitute apt. The simplest supported approach is the NodeSource repository:
# Add the NodeJS 20 LTS repository, then install Node
curl -fsSL https://rpm.nodesource.com/setup_20.x | bash -
dnf install -y nodejs
# Confirm the versions
node -v
npm -v
If you need different Node versions for different apps, install nvm under the service account instead and select a version per project.
05. Root Server: Create a Service Account and Your App
Create a dedicated, unprivileged user that owns the application files and under which the service runs. Do not use root.
# Create a locked-down system user with a home directory
useradd --system --create-home --shell /usr/sbin/nologin appsvc
# Create the app directory and hand it to that user
mkdir -p /opt/myapp
chown -R appsvc:appsvc /opt/myapp
Put your application in /opt/myapp (via git clone, scp, or an rsync deploy) and install its dependencies as the service user:
cd /opt/myapp
sudo -u appsvc npm ci --omit=dev
A minimal server.js that listens only on localhost, so nginx is the only way in, looks like this:
const http = require('http');
const PORT = process.env.PORT || 3000;
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from the VPS\n');
});
// Bind to localhost so the app is only reachable through the reverse proxy
server.listen(PORT, '127.0.0.1', () => {
console.log('Listening on 127.0.0.1:' + PORT);
});
Listen on 127.0.0.1, never 0.0.0.0. That keeps the Node port off the public internet, so the only way in is through nginx, where you control TLS, headers, and access rules.
06. Root Server: Keep the App Alive with systemd
A plain node server.js dies when you log out. Let systemd own the process so it starts on boot, restarts on failure, and logs centrally. Create /etc/systemd/system/myapp.service:
[Unit]
Description=My NodeJS application
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=appsvc
Group=appsvc
WorkingDirectory=/opt/myapp
EnvironmentFile=/etc/myapp/myapp.env
ExecStart=/usr/bin/node /opt/myapp/server.js
Restart=always
RestartSec=3
# Hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/myapp
[Install]
WantedBy=multi-user.target
Enable and start it, then check the status and watch the logs:
systemctl daemon-reload
systemctl enable --now myapp
systemctl status myapp
journalctl -u myapp -f
07. Store Secrets Safely
Keep API keys, database passwords, and tokens out of your code and out of your git repository, on either path.
- Managed cPanel: add them as environment variables in the Setup Node.js App panel. cPanel injects them into your app's environment, and they stay out of your files.
- Root server: use the
EnvironmentFilenamed in the unit above, readable only by root (systemd reads it as root before dropping to the service user):
mkdir -p /etc/myapp
cat > /etc/myapp/myapp.env <<'EOF'
PORT=3000
DATABASE_URL=mysql://appuser:[email protected]:3306/myapp
UPSTREAM_API_KEY=CHANGE_ME
EOF
chmod 600 /etc/myapp/myapp.env
chown root:root /etc/myapp/myapp.env
Your app reads these as process.env.DATABASE_URL, process.env.UPSTREAM_API_KEY, and so on.
Add your environment file and any key material to .gitignore. A secret pushed to a repository must be treated as compromised and rotated, even in a private repo. Enter credentials on the server, never by pasting them into chat, a ticket, or email.
08. Root Server: nginx and HTTPS in Front
nginx terminates TLS on ports 80 and 443 and forwards requests to your Node app on localhost. You need a domain or subdomain with an A record pointing at the server IP (for example api.yourdomain.com). Install nginx:
dnf install -y nginx
systemctl enable --now nginx
Create a server block at /etc/nginx/conf.d/myapp.conf:
server {
listen 80;
server_name api.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Test the config and reload:
nginx -t
systemctl reload nginx
Now add a free Let's Encrypt certificate with Certbot, which also rewrites the server block to redirect HTTP to HTTPS. For more on SSL, see article #68.
dnf install -y certbot python3-certbot-nginx
certbot --nginx -d api.yourdomain.com
# Certbot installs a renewal timer automatically; confirm it:
systemctl list-timers | grep certbot
Because requests now arrive through nginx, your Node app sees 127.0.0.1 as the remote address unless it reads the X-Forwarded-For header set above. If your framework has a trust-proxy setting (for example Express's app.set('trust proxy', 1)), enable it so client IPs and HTTPS detection work correctly.
09. Root Server: Open the Firewall
Our VPS and dedicated server plans ship with the CSF firewall. Inbound web traffic needs ports 80 and 443 open, and your SSH port must stay open or you will lock yourself out. Edit /etc/csf/csf.conf:
# Inbound: keep your SSH port, add the web ports
TCP_IN = "YOUR_SSH_PORT,80,443"
# Outbound: 443 must be open if your app calls external APIs over HTTPS
TCP_OUT = "20,21,22,25,53,80,443,YOUR_SSH_PORT"
Apply the change:
csf -r
Before you reload the firewall, double-check your SSH port is listed in TCP_IN, and keep a second logged-in session open while you test. If a rule change locks you out, the open session lets you undo it.
10. Verify, Deploy, and Where to Go Next
On the root path, confirm the full path works end to end from your own machine:
curl -i https://api.yourdomain.com/
You should get a 200 response over HTTPS. To deploy a new version of the app:
cd /opt/myapp
sudo -u appsvc git pull
sudo -u appsvc npm ci --omit=dev
systemctl restart myapp
Watch the logs with journalctl -u myapp -f while you restart so you catch any startup error immediately. If you deploy from a git repository, article #488 covers deploying Node and React projects in more depth.
A common use of either path is hosting a Model Context Protocol connector that links ChatGPT or Claude to an external API, which adds streaming, OAuth, and token-storage details on top of this base. For that, see the companion guide in this category, "Hosting an MCP Connector for ChatGPT and Claude on a VPS or Dedicated Server".
Want Us to Set It Up or Open a Port?
On a managed cPanel account we handle the server-level pieces for you, and on a root VPS or dedicated server we can help with the firewall and TLS. Tell us your domain, the port your service listens on, and what you are trying to run, and we will point you at the fix or configure it for you.
Open a Support TicketQuick Recap: Pick a Path and Go
If you only remember a few things from this guide, remember these:
- Managed cPanel is the default: run Node through Setup Node.js App, with no root and no server to maintain.
- We handle server-level needs on a managed account, such as streaming or firewall changes, from a support ticket.
- Choose a root VPS or dedicated server only when you need a persistent, always-resident process.
- On the root path, run the app as a dedicated user under systemd, bound to
127.0.0.1, never as root and never on a public port. - Put secrets in cPanel env vars or a root-owned env file, never in the repository, and open only the ports you need.
Last updated October 2026 · Browse all Getting Started articles
