Most developers build their Node.js app on localhost and then struggle when it's time to go live.
The problem is not the app. The problem is the server setup.
Shared hosting cannot run Node.js properly. You need a VPS — and once you set it up right, it just works.
Here is the full guide.
That is it. Let's get started.
Open your terminal and connect:
ssh root@your_server_ip
If you are using a key file:
ssh -i your-key.pem root@your_server_ip
Once connected, update the server first:
apt update && apt upgrade -y
Always do this on a fresh server. It saves you from a lot of problems later.
The cleanest way to install Node.js is via NodeSource:
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -apt install -y nodejs
Check the version:
node -v npm -v
You should see Node 20+ and npm 10+. If you do, you are good.
Navigate to your preferred directory and clone your repo:
cd /var/www git clone https://github.com/your-username/your-app.git cd your-app
Install dependencies:
npm install
If you have a .env file, create it now:
nano .env
Paste your environment variables and save.
Before anything else, confirm your app starts:
node index.js
Or whatever your entry file is. If it runs without errors, move to the next step.
💡 If you see port errors, make sure your app is not trying to bind to a port already in use.
Node.js apps crash. PM2 restarts them automatically.
npm install -g pm2
Start your app with PM2:
pm2 start index.js --name "my-app"
Make it start automatically on server reboot:
pm2 startup pm2 save
Check status anytime:
pm2 status
PM2 is not optional. It is what separates a production app from a hobby project.
You do not want users hitting port 3000 directly. Nginx sits in front and forwards traffic cleanly.
Install Nginx:
apt install nginx -y
Create a config file for your app:
nano /etc/nginx/sites-available/my-app
Paste this:
server {
listen 80;
server_name your_domain_or_ip;
location / {
proxy_pass http://localhost: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;
}
}
Enable the config:
ln -s /etc/nginx/sites-available/my-app /etc/nginx/sites-enabled/ nginx -t systemctl restart nginx
Your app is now accessible on port 80. No port number in the URL.
Never run a production app over plain HTTP.
Install Certbot:
apt install certbot python3-certbot-nginx -y certbot --nginx -d yourdomain.com
Follow the prompts. It will automatically configure HTTPS for you.
SSL renews automatically. You do not have to think about it again.
| Problem | Fix |
|---|---|
| App not loading | Check pm2 status and pm2 logs |
| 502 Bad Gateway | App is not running, check PM2 |
| Port 80 blocked | Check firewall: ufw allow 80 |
| SSL not working | Make sure domain points to your VPS IP |
| Changes not live | Pull from GitHub and restart: pm2 restart my-app |
If your app starts getting real traffic, you will notice:
At that point, the solution is not to rewrite your app. The solution is a bigger VPS with more resources — and proper load handling.
A VPS gives you that flexibility. Shared hosting does not.
Deploying a Node.js app on a VPS is not complicated once you know the steps.
The hard part is choosing cheap hosting that falls apart when real traffic arrives.
Your app deserves better infrastructure than that.
Your Node.js app needs a server that can actually handle it.
Lvato VPS gives you full root access, SSD storage, and reliable uptime — everything you need to deploy and scale your app without limits.
👉 Get your VPS today: https://lvato.com/vps-hosting/