Deploy a Node.js App on Hostinger with Namecheap DNS and StackPath CDN

by Fahim

Running a Node.js process directly exposed to the public internet on a single VPS is asking for trouble. A sudden traffic spike bogs down your event loop, heavy static assets eat up bandwidth, and your server’s raw IP sits out in the open. But putting an edge CDN in front of an origin brings its own set of headaches: 502 Bad Gateway loops, broken SSL handshakes, and logs flooded with the CDN’s IP instead of your actual visitors.

Here’s how I set up a reliable production pipeline: Node.js running under PM2 on a Hostinger KVM VPS, fronted by Nginx, cached at the edge with StackPath CDN, and routed via Namecheap Advanced DNS.

Close-up of server rack fiber connections alongside a terminal running Node.js production deployment scripts
Close-up of server rack fiber connections alongside a terminal running Node.js production deployment scripts

The Architecture: Origin, Edge, and DNS Layers

Before jumping into the terminal, here’s how the traffic actually travels through the stack:

  • Namecheap DNS: Handles your apex and www records, routing visitor traffic to StackPath’s Anycast edge network via ALIAS or CNAME records.
  • StackPath CDN: Terminates edge SSL, serves cached static assets (images, client bundles, fonts) directly from the nearest PoP, and forwards dynamic requests (/api/*) straight back to Hostinger.
  • Hostinger VPS: An Ubuntu 22.04 LTS instance running Nginx on ports 80 and 443. Nginx handles local SSL, manages reverse-proxy buffering, and proxies traffic locally to our Node app listening on port 3000 under PM2.

If you’re not sure how to wire your root domain properly without breaking email or existing records, check out our guide on pointing an apex domain to a CNAME in Namecheap DNS with ALIAS records.

Step 1: Prepare Your Node.js App for Production

Don’t bind your app to 0.0.0.0. Bind it to 127.0.0.1 so only local processes (Nginx) can talk to it. You also need to trust the reverse proxy headers so Express knows how to read client IP addresses.

Here’s a minimal Express setup that handles proxy headers correctly:

const express = require('express');
const path = require('path'); const app = express();
const PORT = process.env.PORT || 3000; // Trust reverse proxies (Nginx + StackPath)
app.set('trust proxy', true); // Serve static files with aggressive cache headers
app.use('/static', express.static(path.join(__dirname, 'public'), { maxAge: '7d', etag: true
})); // Health check endpoint for StackPath
app.get('/healthz', (req, res) => { res.status(200).json({ status: 'healthy', timestamp: new Date().toISOString() });
}); // Sample API endpoint displaying client IP
app.get('/api/info', (req, res) => { res.json({ message: 'Hello from Hostinger origin!', clientIp: req.ip, protocol: req.protocol });
}); app.listen(PORT, '127.0.0.1', () => { console.log(`Node app running on http://127.0.0.1:${PORT}`);
});

That app.set('trust proxy', true) line is critical. Skip it, and Express will treat every incoming request as if it came from 127.0.0.1 (Nginx) instead of reading the real client IP passed through StackPath’s X-Forwarded-For header. You can read more about how Express handles proxies in the official Express production best practices.

Step 2: Provision Node.js and PM2 on Hostinger

SSH into your Hostinger VPS. First, pull in the NodeSource repo for Node.js 20 LTS and install it alongside PM2.

Run this on your VPS:

# Update package index
sudo apt update && sudo apt upgrade -y # Install curl and build tools
sudo apt install -y curl build-essential git # Add NodeSource Node.js 20 repository
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - # Install Node.js
sudo apt install -y nodejs # Verify versions
node -v
npm -v # Install PM2 globally to manage node processes
sudo npm install -g pm2

Make sure node -v returns v20.x.x. Next, drop your application into /var/www/my-node-app and grab the dependencies.

Set up the app folder and install modules:

sudo mkdir -p /var/www/my-node-app
sudo chown -R $USER:$USER /var/www/my-node-app
cd /var/www/my-node-app # Copy your project files or clone git repo here
npm install --production

Fire up the process with PM2 and generate the systemd startup hook so your app boots back up if the server restarts:

# Start the Node.js server under PM2
pm2 start server.js --name "node-app" # Save the active list for automatic recovery
pm2 save # Generate and run startup script
pm2 startup systemd

Run pm2 status to confirm it shows online. For zero-downtime cluster setups and lifecycle scripts, head over to the PM2 documentation.

Step 3: Configure Nginx as the Reverse Proxy on Hostinger

Don’t ever bind Node directly to port 80 or 443 in production. Nginx is far better at handling TLS handshakes, dropping malformed requests, and buffering slow clients before they tie up Node’s event loop.

Install Nginx:

sudo apt install -y nginx

Create a new server block at /etc/nginx/sites-available/my-node-app.conf:

sudo nano /etc/nginx/sites-available/my-node-app.conf

Paste this config in, swapping out example.com with your actual domain:

server { listen 80; listen [::]:80; server_name example.com www.example.com; # StackPath / Let's Encrypt verification path location /.well-known/acme-challenge/ { root /var/www/html; } location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; # Forwarded client IP headers 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; # Timeouts proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; }
}

Enable the site, unlink the default block, and test the syntax:

sudo ln -s /etc/nginx/sites-available/my-node-app.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Now issue an SSL certificate on the origin with Certbot. StackPath needs to connect to Hostinger over HTTPS, so we need a valid certificate living directly on the origin:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com

For a deeper dive into origin certificates and cipher suites, check out our walkthrough on configuring end-to-end SSL with Namecheap, StackPath, and Hostinger.

Step 4: Create the StackPath CDN Site

With the origin running, let’s put StackPath in front of it.

  1. Log into your StackPath dashboard and hit Sites > Create Site.
  2. Select CDN.
  3. Enter your domain name (e.g., example.com).
  4. Set Origin Type to IP Address.
  5. Enter your Hostinger VPS public IPv4 address.
  6. Set the Origin Connection to port 443 with HTTPS enabled.

StackPath will hand you an Edge CNAME target (like example.stackpathdns.com) along with Anycast IP addresses.

Next, hop into CDN > EdgeRules and create two critical rules:

  • Static Assets: Match extensions *.js, *.css, *.png, *.jpg, *.svg, *.woff2 and set the edge cache TTL to 7 days.
  • API Routes: Match /api/* and set the Cache Action to Bypass Cache. If you skip this, StackPath will cache your dynamic JSON payloads and your users will see stale data.

If you push frequent frontend updates, take a look at our guide on how to automatically purge StackPath CDN cache with GitHub Actions.

Step 5: Point Namecheap DNS to StackPath

Head to Namecheap, open your Domain List, and click Manage next to your domain. Make sure your nameservers are set to Namecheap BasicDNS, then click over to Advanced DNS.

Clear out any existing A or CNAME records pointing straight to Hostinger for @ and www. Replace them with these:

  • Type: ALIAS Record (or A Record using StackPath’s edge IPs if your registrar setup doesn’t offer ALIAS)
  • Host: @
  • Value: example.stackpathdns.com
  • TTL: Automatic (or 1 min while testing)
  • Type: CNAME Record
  • Host: www
  • Value: example.stackpathdns.com
  • TTL: Automatic

Save the changes. Propagation usually takes anywhere from 5 to 30 minutes. Verify the edge resolution with dig:

dig +short example.com
dig +short www.example.com

You should see StackPath’s Anycast addresses returned, not your raw Hostinger VPS IP.

Step 6: Fix Real Visitor IP Addresses in Nginx

The first time I deployed this, I hit an annoying issue: all my access logs and Node’s req.ip showed StackPath’s edge IP instead of the visitor’s real address. That breaks rate-limiting, geo-routing, and security auditing.

We fix this by telling Nginx’s http_realip_module to trust StackPath’s proxies and extract the true visitor IP from X-Forwarded-For.

Create a config file at /etc/nginx/conf.d/realip.conf:

sudo nano /etc/nginx/conf.d/realip.conf

Add StackPath’s IP blocks as trusted proxies and set the header directive:

# StackPath Edge IP Ranges
set_real_ip_from 151.139.128.0/18;
set_real_ip_from 198.252.110.0/24;
set_real_ip_from 199.231.112.0/22;
set_real_ip_from 209.197.0.0/17; # Read visitor IP from X-Forwarded-For
real_ip_header X-Forwarded-For;
real_ip_recursive on;

Test the syntax and reload Nginx:

sudo nginx -t
sudo systemctl reload nginx

If you’re dealing with multiple proxy layers or running Apache on other boxes, see our guide on how to restore real visitor IP addresses behind StackPath CDN on Nginx and Apache.

Step 7: Verify Cache and Origin Communication with curl

Once DNS settles, open a local terminal and test your setup using curl -I to inspect the response headers.

Check a static asset first:

curl -I https://example.com/static/style.css

Look at the headers:

HTTP/2 200
server: StackPath
content-type: text/css; charset=UTF-8
cache-control: public, max-age=604800
x-cache: HIT

You want to see x-cache: HIT. The very first request will likely return x-cache: MISS while the edge fetches from your VPS. Hit it a second time, and it should immediately flip to HIT.

Now test your dynamic API route:

curl -i https://example.com/api/info

Inspect the JSON response:

{ "message": "Hello from Hostinger origin!", "clientIp": "203.0.113.45", "protocol": "https"
}

If clientIp matches your actual public IP rather than an internal address or a StackPath node, your proxy chain and real-IP setup are dialed in.

Frequently Asked Questions

Can I deploy this on Hostinger shared or Cloud hosting instead of a VPS?

Hostinger Cloud and shared plans have a built-in Node.js selector in hPanel where you can set an entry file like server.js without touching Nginx configs. But a KVM VPS gives you full root control. That means you can tune Nginx proxy buffers, manage PM2 cluster workers, and lock down your UFW firewall so only StackPath’s IP ranges can touch port 443.

Why does my app show 502 Bad Gateway after deploying?

A 502 means Nginx can’t connect to port 3000. Start by running pm2 status on your VPS to verify the Node app didn’t crash on boot. Then test the local port directly with curl -I http://127.0.0.1:3000. If PM2 is caught in an infinite restart loop, inspect the error output with pm2 logs node-app --lines 50—usually it’s a missing environment variable or a syntax error.

Do I need an SSL certificate on Hostinger if StackPath provides Edge SSL?

Yes. If you skip the origin certificate, traffic between StackPath and your Hostinger VPS travels over unencrypted HTTP on port 80. Running Certbot on your VPS guarantees full end-to-end encryption so API payloads, session cookies, and authorization headers are never exposed across the open web.

How do I push new code updates without downtime?

Don’t use pm2 restart in production—it kills the process before starting the new one. Instead, pull your changes and run pm2 reload node-app. PM2 handles a rolling zero-downtime reload by spawning new worker processes before retiring the old ones.

Next Steps

Now that your Node.js backend is running smoothly behind StackPath and resolving through Namecheap, your origin is protected from brute-force traffic spikes and static files are delivered fast from the edge. If you’re pairing this backend with a modern frontend, check out our guide on how to deploy a React SPA on Hostinger with StackPath CDN and Namecheap DNS.

all_in_one_marketing_tool