DEV Community

Cover image for From Localhost to Cloud: Deploying a Node.js Bot app to AWS EC2 (My 3rd Deployment, Different Method!)
officiabreezy
officiabreezy

Posted on

From Localhost to Cloud: Deploying a Node.js Bot app to AWS EC2 (My 3rd Deployment, Different Method!)

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

  1. Log in to AWS Console → EC2 → Launch Instance
  2. Configure:

    • OS: Ubuntu Server 22.04 LTS (Free tier eligible)
    • Instance type: t2.micro (Free tier)
    • Key pair: Create new → download the .pem file (keep this safe!)
    • Security Group: Open ports 22 (SSH), 80 (HTTP), 443 (HTTPS)
  3. 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>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 repo scope)

# Clone using your token
git clone https://<YOUR_TOKEN>@github.com/yourusername/your-repo.git

# Navigate into project
cd your-repo
Enter fullscreen mode Exit fullscreen mode

🔐 Security tip: Never hardcode tokens in your source code. Use environment variables with a .env file in production.


Step 5: Install Dependencies

# Create logs directory (if your app needs it)
mkdir -p logs

# Install npm packages
npm install
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

You should see something like:

┌────┬──────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name     │ mode     │ ↺    │ status    │ cpu      │ memory   │
├────┼──────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0  │ my-app   │ fork     │ 0    │ online    │ 0%       │ 45.0mb   │
└────┴──────────┴──────────┴──────┴───────────┴──────────┴──────────┘
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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/
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  1. There's no single "best" deployment method — the right tool depends on your project complexity and update frequency.

  2. Try multiple approaches — each method teaches you something different about how servers actually work.

  3. PM2 is a game changer for Node.js deployments — crash recovery and systemd integration make it production-ready with minimal setup.

  4. AWS Free Tier is perfect for learning — t2.micro with 6.8GB disk is more than enough for simple Node.js apps.

  5. 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)