How to Deploy Multiple Node.js Apps on Ubuntu with Bash
Stop Deploying by Hand. Seriously.
You built a killer Node.js app. Then you built another. Now you're SSH-ing into your Ubuntu server every time you push a git commit, manually pulling code, running npm install, and praying nothing breaks. It's exhausting. Manual deployments are the enemy of sleep. We need a nodejs deployment script that actually does the heavy lifting for us. Let's fix this mess.
Enter PM2 and Bash: Your New Best Friends
Bash isn't just for graybeards. It's raw power. Combine a solid bash script with PM2—the undisputed king of Node process managers—and you get magic. No massive Jenkins pipelines. No heavy container orchestration if you don't actually need it. Just clean, raw pm2 automation ubuntu style. It keeps your apps alive, restarts them if they crash, and manages your logs. Let's write some code.
The Anatomy of a Bulletproof Script
Here's the plan. We write a single file. Let's call it deploy.sh. It loops through your app directories, pulls the latest main branch, installs dependencies, and tells PM2 to reload. Simple. The trick is making it idempotent. Run it once, it works. Run it ten times, it still works. This bash app deployment approach means you can scale to five, ten, or twenty apps on the exact same machine without sweating.
Handling Port Collisions Like a Pro
Multiple apps mean multiple ports. App A runs on 3000. App B runs on 3001. Hardcode this, and you'll hate yourself next month. Pass the port as an environment variable right inside your bash loop. Let PM2 handle the environment injection. Your script reads a config array, passes the variables to PM2, and binds everything cleanly. Then, you just let Nginx reverse proxy the traffic. Zero downtime. Zero headache.
Fire It Off and Go Grab a Drink
Give your script executable permissions. Just type chmod +x deploy.sh. Run it. Watch the terminal output as PM2 spins up your clustered Node apps in beautiful, color-coded tables. That's it. Your server is now an automated machine. Next time you push a feature, just trigger the script. You're done here.