🚀 How to Deploy an Express.js App on an Ubuntu Server using PM2 and Nginx
Deploying your Express.js app to a production server might sound daunting at first, but with tools like PM2 for process management and Nginx as a reverse proxy, the process becomes smooth and scalable.
In this blog, I’ll walk you through deploying a Node.js/Express application on an Ubuntu server. We'll use PM2 to keep our app running and Nginx to handle traffic and provide SSL termination.
🛠️ Prerequisites
Before diving in, make sure you have the following:
- Ubuntu server: A running Ubuntu server (preferably Ubuntu 20.04 or later)
- Root access: or a user on that OS with
sudo
privileges - App: Your Express.js app ready to deploy
- Domain: A domain name (optional, but needed for SSL)
📁 Step 1: Connect to Your Server
First of all, we need to log into the server using SSH and upgrade all Ubuntu dependencies.
ssh your_user@your_server_ip
sudo apt update && sudo apt upgrade -y
📦 Step 2: Install Node.js and npm
We’ll use NVM (Node Version Manager) to install Node.js:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc
nvm install --lts
Verify installation:
node -v
npm -v
📁 Step 3: Get Your Express App to the Server
You can either clone the project from GitHub or upload it manually using SCP/FTP. If you're cloning from GitHub, it's recommended to use SSH for secure access.
git clone git@github.com:yourusername/your-repo.git
cd your-repo
npm install
📡 Step 4: Run Dev Server (Optional)
For testing purposes, you can run the app using:
node app.js
You can then access it at: http://your_server_ip:PORT
🔄 Step 5: Install and Use PM2
Install PM2 globally:
npm install -g pm2
Start your app with PM2:
pm2 start app.js --name myapp
Enable auto-restart on system reboot:
pm2 save
pm2 startup
Follow the instructions shown to run the generated command.
🌐 Step 6: Install and Configure Nginx
Install Nginx:
sudo apt install nginx -y
Create a new Nginx config file:
sudo nano /etc/nginx/sites-available/myapp
Paste this configuration (adjust domain and port):
server {
listen 80;
server_name yourdomain.com;
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 site and restart Nginx:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
🔒 Step 7: (Optional) Enable HTTPS with Let's Encrypt
Install Certbot:
sudo apt install certbot python3-certbot-nginx -y
Request a free SSL certificate:
sudo certbot --nginx -d yourdomain.com
Set up auto-renew:
sudo systemctl enable certbot.timer
✅ Final Checklist
- ✅ App running via PM2:
pm2 list
- ✅ Nginx serving your app:
systemctl status nginx
- ✅ HTTPS configured (if domain available)
- ✅ Auto-start enabled on reboot:
pm2 save && pm2 startup
🎉 Conclusion
Congratulations! Your Express.js app is now deployed on an Ubuntu server, managed by PM2, and served by Nginx. This setup ensures that your app is production-ready, stable, and scalable.
If you're hosting multiple apps or domains, consider using Nginx with subdomains or even Docker + Nginx proxy manager for more advanced deployments.