Host a React + Node.js app on Hostinger VPS with Nginx
Shared hosting is fine for static React apps, but the moment you add a Node.js backend — an API, authentication, a WebSocket server — you need a real server. Hostinger's VPS plans give you full root access, a public IP, and the freedom to run whatever you want. This guide walks you through the entire setup: provisioning the VPS, installing Node.js, configuring Nginx as a reverse proxy, deploying your React frontend, and keeping everything running with PM2.
What you'll need
- A Hostinger VPS plan (KVM 1 or higher — KVM 2 recommended for comfortable headroom)
- A React + Vite (or CRA) frontend
- A Node.js backend (Express, Fastify, or similar)
- Basic comfort with the terminal and SSH
Step 1: Provision your VPS
After purchasing a Hostinger VPS:
- Log in to hPanel and go to VPS
- Choose Ubuntu 22.04 as your OS — it's well supported, has a long support window, and most tutorials online target it
- Set a root password or upload an SSH key (SSH key is strongly recommended)
- Note your VPS IP address from the dashboard
SSH into your server:
ssh root@YOUR_VPS_IP First thing — update the system:
apt update && apt upgrade -y Step 2: Create a non-root user
Running everything as root is a security risk. Create a dedicated user:
adduser deploy
usermod -aG sudo deploy If you're using SSH keys, copy them to the new user:
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy From now on, SSH in as deploy instead of root:
ssh deploy@YOUR_VPS_IP Step 3: Install Node.js
Use NVM to install Node.js — it avoids permission issues and makes version management easy:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc
nvm install 20
nvm use 20
node --version You should see v20.x.x. Node 20 is the current LTS and what you want for production.
Step 4: Install PM2
PM2 keeps your Node.js process alive after crashes and server restarts:
npm install -g pm2 Step 5: Install Nginx
Nginx will sit in front of your Node.js app, handling HTTPS termination and serving your React frontend's static files:
sudo apt install nginx -y
sudo systemctl enable nginx
sudo systemctl start nginx Visit your VPS IP in a browser — you should see the Nginx welcome page. That confirms it's running.
Step 6: Upload your app
Clone your repo directly on the server:
cd /var/www
sudo mkdir myapp
sudo chown deploy:deploy myapp
cd myapp
git clone YOUR_REPO_URL .
npm install
npm run build If your repo has both frontend and backend, the structure might look like:
/var/www/myapp/
dist/ ← built React frontend
server/ ← Node.js backend
package.json Step 7: Start your Node.js backend with PM2
cd /var/www/myapp
pm2 start server/index.js --name myapp Make PM2 restart on server reboot:
pm2 startup PM2 will print a command — copy and run it. Then save the current process list:
pm2 save Check your app is running:
pm2 status
pm2 logs myapp Step 8: Configure Nginx
Create a new Nginx config:
sudo nano /etc/nginx/sites-available/myapp Paste this configuration (replace YOUR_DOMAIN and adjust the port your Node.js app listens on):
server {
listen 80;
server_name YOUR_DOMAIN www.YOUR_DOMAIN;
root /var/www/myapp/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://localhost:3001;
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;
}
} - Serves your React
dist/folder for all non-API routes - The
try_filesline handles React Router — unknown paths fall back toindex.html - Proxies any request starting with
/api/to your Node.js backend on port 3001
Enable the config:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx nginx -t tests your config for syntax errors before reloading — always run it.
Step 9: Point your domain to the VPS
At your domain registrar (or in Hostinger's DNS settings), create A records:
Type: A Name: @ Value: YOUR_VPS_IP TTL: 3600
Type: A Name: www Value: YOUR_VPS_IP TTL: 3600 DNS propagation takes up to 24 hours but is usually faster.
Step 10: Enable HTTPS with Let's Encrypt
Once your domain is pointing at the VPS, install Certbot:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d YOUR_DOMAIN -d www.YOUR_DOMAIN Certbot will automatically modify your Nginx config to handle HTTPS and set up auto-renewal. Confirm with:
sudo certbot renew --dry-run Deploying updates
When you push new code, SSH into the server and run:
cd /var/www/myapp
git pull
npm install
npm run build
pm2 restart myapp You can wrap this in a deploy.sh script and run it with one command. For fully automated deploys, add a GitHub Action that SSHes into the server and runs these commands on every push to main.
Useful PM2 commands
pm2 status # see all running processes
pm2 logs myapp # tail logs
pm2 restart myapp # restart after code changes
pm2 stop myapp # stop the process
pm2 monit # live dashboard Troubleshooting
502 Bad Gateway
Nginx can't reach your Node.js app. Check PM2 status (pm2 status) and make sure the port in your Nginx config matches the port your app listens on.
React Router 404 on refresh
Make sure the try_files $uri $uri/ /index.html line is in your Nginx config. This is the Nginx equivalent of the .htaccess fix on shared hosting.
App crashes after reboot
Run pm2 startup and pm2 save again. Make sure you ran the command PM2 printed after pm2 startup.
SSL certificate fails
Your domain isn't pointing at the VPS yet. Wait for DNS to propagate and try again.
Permission denied on /var/www
Make sure your deploy user owns the app directory: sudo chown -R deploy:deploy /var/www/myapp
Summary
A Hostinger VPS with Nginx and PM2 is a solid, production-ready setup for a React + Node.js app. You get full control, no function timeouts, persistent storage, and a single monthly bill. The setup takes a couple of hours the first time, but once it's done deployments are fast and the stack is easy to maintain.
Plans start from $4.99/mo with full root access and SSD storage.
Get a Hostinger VPS →