This guide outlines the steps required to deploy your Node.js application on an Ubuntu/Debian server using Nginx as a reverse proxy, nvm for Node.js version management, and PM2 for process management. It also covers setting up SSL with Let’s Encrypt and configuring the UFW firewall.
Update your package list and install Nginx:
sudo apt update && sudo apt install nginx -yUsing nvm allows you to easily manage multiple versions of Node.js.
-
Install nvm:
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.4/install.sh | bash -
Reload your shell environment:
source ~/.bashrc
-
Install the latest Node.js version:
nvm install node
-
Use the latest Node.js version:
nvm use node
-
Verify the installation:
node -v
Create a directory for your website:
sudo mkdir -p /var/www/web/-
If uploading locally: Use SFTP or scp:
scp web.zip root@<YOUR_VPS_IP>:/var/www/web
Then:
cd /var/www/web apt install unzip unzip web.zip -
If cloning from a repository:
git clone <YOUR_REPO_URL> /var/www/web
Navigate to your application directory and install dependencies:
cd /var/www/web
npm installIf your application requires environment variables, create a .env file:
nano .envThen add your variables (example):
PORT=3000
MONGO_URI=mongodb://localhost:27017/mydb
sudo npm install -g pm2For frameworks like React, Vue.js, Angular, Svelte, Next.js, or if using TypeScript:
npm run build-
For npm-based start scripts:
pm2 start npm --name "myapp" -- start -
For a specific entry file (e.g.,
src/index.js):pm2 start src/index.js --name "web"
pm2 startup
pm2 saveCheck the logs to verify your application is running correctly:
pm2 logsFor more detailed logs (last 1000 lines):
pm2 logs --lines 1000Create a configuration file for your domain (e.g., web1.com):
sudo nano /etc/nginx/sites-available/web1.comserver {
listen 80;
server_name web1.com;
location /.well-known/acme-challenge/ {
root /var/www/html;
allow all;
}
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
location /api/ws {
proxy_pass http://127.0.0.1:3000/api/ws;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
}server {
listen 80;
server_name web1.com www.web1.com;
location /.well-known/acme-challenge/ {
root /var/www/html;
allow all;
}
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;
}
}Create a symbolic link to enable your site:
sudo ln -s /etc/nginx/sites-available/web1.com /etc/nginx/sites-enabled/-
Test the configuration for syntax errors:
sudo nginx -t
-
Restart Nginx:
sudo systemctl restart nginx
sudo apt install certbot python3-certbot-nginx -yRun the Certbot command to automatically configure SSL for your domain:
sudo certbot --nginxTest the renewal process with:
sudo certbot renew --dry-runEnsure only essential services (SSH, HTTP, HTTPS) are allowed:
sudo apt install ufw -y
sudo ufw allow OpenSSH
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enableYour Node.js application should now be running securely behind Nginx on your specified domain. Should you encounter any issues, verify the logs for both PM2 and Nginx and adjust configurations as necessary.
Happy deploying!
Made with ❤️ by Sahil Hossain