A practical walkthrough of deploying a Node.js bot app to AWS EC2 using GitHub + PM2 + systemd — my third EC2 deployment using a completely different approach each time
From Localhost to Cloud: Deploying a Node.js Bot App to AWS EC2
This is my third time deploying to AWS EC2, and I've used a different method each time:
- 🐳 1st deployment — Docker containers
- 📁 2nd deployment — Manual file upload (SCP)
- 🔄 3rd deployment (this one) — GitHub + PM2 + systemd
Each approach taught me something unique. This time I wanted a workflow that was easy to update, automatically recovers from crashes, and survives server reboots — without the overhead of Docker for a simple Node.js app.
Here's exactly what I did, step by step.
What I Built
A reporter bot that:
- Listens for new members joining servers
- Sends real-time notifications with member details
- Logs all activity with automatic daily log rotation (7-day retention)
- Runs 24/7 in the cloud — even when my PC is off
Tech stack: Node.js, discord.js, axios, winston, PM2, AWS EC2 (Ubuntu 22.04)
Step 1: Launch an EC2 Instance
- Log in to AWS Console → EC2 → Launch Instance
-
Configure:
- OS: Ubuntu Server 22.04 LTS (Free tier eligible)
- Instance type: t2.micro (Free tier)
-
Key pair: Create new → download the
.pemfile (keep this safe!) - Security Group: Open ports 22 (SSH), 80 (HTTP), 443 (HTTPS)
Click Launch Instance and wait for it to start
Step 2: Connect to Your EC2 Instance
From your terminal:
# Make your key file readable (Linux/Mac/Git Bash)
chmod 400 your-key.pem
# Connect via SSH
ssh -i your-key.pem ubuntu@<your-ec2-public-ip>
You should now see the Ubuntu welcome screen. You're in! 🎉
Step 3: Set Up the Server
Once connected, install the required tools:
# Update system packages
sudo apt update && sudo apt upgrade -y
# Install Node.js (v20)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# Verify installation
node --version
npm --version
# Install Git
sudo apt install git -y
# Install PM2 globally (process manager)
sudo npm install -g pm2
Step 4: Clone Your Repository from GitHub
⚠️ GitHub no longer accepts passwords. Use a Personal Access Token (PAT) instead.
Go to: GitHub → Settings → Developer Settings → Personal Access Tokens → Generate New Token (check the
reposcope)
# Clone using your token
git clone https://<YOUR_TOKEN>@github.com/yourusername/your-repo.git
# Navigate into project
cd your-repo
🔐 Security tip: Never hardcode tokens in your source code. Use environment variables with a
.envfile in production.
Step 5: Install Dependencies
# Create logs directory (if your app needs it)
mkdir -p logs
# Install npm packages
npm install
You should see all packages installed successfully.
Step 6: Start Your App with PM2
PM2 is a production process manager for Node.js. It keeps your app running, auto-restarts on crashes, and manages logs.
# Start the application
pm2 start index.js --name "my-app"
# Check it's running
pm2 status
You should see something like:
┌────┬──────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name │ mode │ ↺ │ status │ cpu │ memory │
├────┼──────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0 │ my-app │ fork │ 0 │ online │ 0% │ 45.0mb │
└────┴──────────┴──────────┴──────┴───────────┴──────────┴──────────┘
Status: online ✅ — your app is running!
Step 7: Configure Auto-Start on Reboot
This is the most important step for a "set it and forget it" deployment:
# Generate the startup command
pm2 startup
# PM2 will output a command — copy and run it. It looks like:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu
# Save the current process list
pm2 save
Now your app will automatically start whenever the EC2 instance reboots!
Step 8: Verify Everything is Working
# View live logs
pm2 logs my-app
# Monitor CPU and memory
pm2 monit
# Check disk space
df -h
Comparing My 3 Deployment Methods
| Feature | Docker | Manual SCP | GitHub + PM2 |
|---|---|---|---|
| Setup time | Medium | Fast | Fast |
| Update process | Rebuild image | Re-upload files | git pull |
| Auto-restart | With compose | Manual | ✅ Built-in |
| Boot persistence | With compose | Manual | ✅ systemd |
| Best for | Complex apps | Learning | Solo projects |
| Learning curve | High | Low | Medium |
What I Learned From Each:
🐳 Docker: Great for complex apps with multiple services. Containerization ensures consistency across environments. But for a simple Node.js bot, it felt like overkill.
📁 Manual SCP: Forced me to understand exactly what's happening on the server — no abstractions. Best for learning fundamentals but tedious for frequent updates.
🔄 GitHub + PM2 (this one): Sweet spot for solo projects. Easy updates (git pull && pm2 restart), built-in crash recovery, and systemd integration for boot persistence.
Disk Space Management
One thing to keep in mind — my bot generates daily log files. Here's what my disk usage looked like after deployment:
$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/root 6.8G 3.2G 3.6G 47% /
$ du -sh ~/reporter/logs/
232K /home/ubuntu/reporter/logs/
47% used with plenty of headroom. My winston logger is configured with maxFiles: "7d" which automatically deletes logs older than 7 days — keeping disk usage minimal.
Useful PM2 Commands
# Check status
pm2 status
# View live logs
pm2 logs my-app
# View last 100 lines
pm2 logs my-app --lines 100
# Restart app
pm2 restart my-app
# Stop app
pm2 stop my-app
# Monitor CPU/Memory in real-time
pm2 monit
# List all processes
pm2 list
Key Takeaways
There's no single "best" deployment method — the right tool depends on your project complexity and update frequency.
Try multiple approaches — each method teaches you something different about how servers actually work.
PM2 is a game changer for Node.js deployments — crash recovery and systemd integration make it production-ready with minimal setup.
AWS Free Tier is perfect for learning — t2.micro with 6.8GB disk is more than enough for simple Node.js apps.
Always use environment variables for sensitive tokens in production — never hardcode credentials in your source code.
Conclusion
This GitHub + PM2 + systemd approach has become my favorite for solo Node.js projects. It strikes the right balance between simplicity and reliability — easy to set up, easy to update, and runs 24/7 without babysitting.
If you're just getting started with cloud deployments, I'd recommend this exact stack. Once you're comfortable, try Docker for more complex multi-service applications.
Happy deploying! 🚀
Have you deployed to AWS EC2? What method do you prefer? Drop a comment below!
Top comments (0)