DEV Community

Cover image for 10 Mistakes Developers Make When Deploying to AWS EC2
Arunangshu Das
Arunangshu Das

Posted on

10 Mistakes Developers Make When Deploying to AWS EC2

Amazon EC2 is powerful. It gives developers the freedom to spin up virtual machines in minutes, customize configurations, and run applications just the way they want. But with great power comes a thousand ways to mess things up.

If you’ve ever spent hours debugging a broken EC2 instance, wondering why the app worked locally but not on the cloud, you’re not alone.

1. Ignoring Security Groups and Inbound Rules

The Mistake:
Developers often launch an EC2 instance and then wonder why they can’t SSH into it or access it via HTTP. The issue? Incorrectly configured security groups or default settings that block all traffic.

What Happens:

  • Your app might be running fine but isn’t accessible externally.
  • SSH connections are refused.
  • Ports like 80, 443, or 3000 aren’t open.

Real-World Pain:
You’ve deployed a Node.js app on port 3000, but every browser request returns a timeout. You waste hours checking server logs and app code, not realizing the EC2 instance is blocking incoming traffic.

How to Fix It:

  • When creating your EC2 instance, configure the security group to allow required inbound traffic (e.g., TCP on ports 22, 80, 443, 3000).
  • Keep security tight. Avoid setting "All traffic" from "0.0.0.0/0" unless absolutely necessary.
  • Use custom rules for your application ports and restrict by IP when possible.

2. Not Using Elastic IPs

The Mistake:
Using the public IP assigned automatically by AWS and assuming it won’t change.

What Happens:

  • Every time you stop and start your EC2 instance, the public IP changes.
  • DNS records break, services relying on fixed IPs go down.

Real-World Pain:
You update your DNS to point to the EC2’s public IP. The next morning, your website is unreachable. The instance was restarted, and the IP changed—breaking your setup.

How to Fix It:

  • Allocate an Elastic IP address in AWS.
  • Associate it with your EC2 instance.
  • Now the public IP is static until you release it.

Elastic IPs are free as long as they’re attached to a running instance, so use them wisely.

3. Deploying Without Load Balancing or Auto Scaling

The Mistake:
Relying on a single EC2 instance to handle all traffic—no matter how big or small.

What Happens:

  • App crashes under high load.
  • Zero redundancy—if the instance fails, everything goes down.
  • Manual scaling becomes a nightmare.

Real-World Pain:
You get featured on Hacker News. Traffic explodes. Your lone EC2 instance can't handle it, and your site crashes at the exact moment it could have gone viral.

How to Fix It:

  • Use Elastic Load Balancing (ELB) to distribute traffic across multiple instances.
  • Implement Auto Scaling Groups (ASGs) to spin up/down instances based on CPU, memory, or custom metrics.
  • This combo ensures high availability and performance under load.

4. Storing Application Data on the Instance Itself

The Mistake:
Saving app files, user uploads, or database files directly to the EC2 root volume.

What Happens:

  • All data is lost if the instance is terminated.
  • Limited scalability and backup options.

Real-World Pain:
You store user uploads in /var/www/app/uploads. An intern accidentally terminates the instance, and poof—gigabytes of production data are gone.

How to Fix It:

  • Store persistent data in services designed for it:

  * Use Amazon S3 for user uploads.
  * Use RDS or Amazon Aurora for databases.
  * Use EFS (Elastic File System) if you need shared storage across instances.
 
This separation ensures your data survives, even if your EC2 instance doesn't.

5. Hardcoding Secrets and Environment Variables

The Mistake:
Placing AWS keys, database passwords, and secrets directly in your codebase or config.js files.

What Happens:

  • Security vulnerabilities.
  • Leaks if your repo is public (or accidentally made public).
  • Pain when updating secrets across environments.

Real-World Pain:
Your GitHub repo goes public for 10 minutes. That’s long enough for bots to scrape your AWS keys and rack up a \$2,000 EC2 bill in a day.

How to Fix It:

  • Use AWS Systems Manager Parameter Store or AWS Secrets Manager.
  • Use environment variables and inject them at runtime via launch templates, Docker secrets, or .env files (never committed to source control).
  • Avoid console.log(process.env.SECRET_KEY)—yes, we’ve all done it in dev.

6. Not Setting Up Logging and Monitoring

The Mistake:
Deploying the app and assuming “it just works” without setting up visibility into its behavior.

What Happens:

  • You’re flying blind when something breaks.
  • Logs are lost when the instance is restarted.
  • You can't detect performance issues or attacks.

Real-World Pain:
You get a call at 2 AM: “The API is down.” You SSH into EC2, only to find the logs wiped after a reboot. You have no idea what happened.

How to Fix It:

  • Integrate with Amazon CloudWatch Logs and CloudWatch Metrics.
  • Stream logs from your app (stdout, stderr, custom files) to CloudWatch.
  • Set up Alarms for CPU spikes, memory leaks, and disk usage.
  • Use X-Ray for tracing performance bottlenecks.

Pro tip: Install the CloudWatch Agent for system-level metrics.

7. Failing to Regularly Update and Patch Instances

The Mistake:
Deploying once and forgetting to apply OS-level updates, package patches, or software upgrades.

What Happens:

  • Vulnerabilities accumulate.
  • Your instance becomes an easy target.
  • Old dependencies cause compatibility issues.

Real-World Pain:
Your EC2 instance runs Ubuntu 18.04 with Node.js v10. You try to deploy an updated app using async/await, and it crashes because the runtime is too old.

How to Fix It:

  • Regularly patch your EC2 instances using SSM Patch Manager.
  • Automate updates with cron jobs or CI/CD pipelines.
  • Use Amazon Linux 2023, which has rolling updates and support.

Even better? Containerize your app so you can manage runtime versions in Docker images.

8. Manual Configuration Instead of Infrastructure as Code

The Mistake:
Clicking around the AWS console to launch instances, set up security groups, configure volumes, etc.—with no documentation or reproducibility.

What Happens:

  • You can’t recreate the environment.
  • Drift occurs between dev, staging, and prod.
  • Team collaboration suffers.

Real-World Pain:
You set up EC2 perfectly. A teammate asks you to replicate it. You forget some IAM rule or EBS config—and now they get 403s and random errors.

How to Fix It:

  • Use Infrastructure as Code (IaC) tools like Terraform, AWS CloudFormation, or Pulumi.
  • Store configs in version control.
  • Automate deployments and rollbacks.
  • Share and reuse templates across environments.

IaC isn’t just for DevOps pros—it’s for every developer who wants consistency and sanity.

9. Using the Default EC2 AMI Without Optimization

The Mistake:
Launching from the default Amazon Linux or Ubuntu AMI without customizing it for your stack.

What Happens:

  • Boot time is slower.
  • Extra configuration is needed after launch.
  • Missed optimization opportunities.

Real-World Pain:
Every time you spin up an EC2 instance, you install Nginx, Node.js, PM2, and 10 other packages—manually. It takes 30 minutes just to get started.

How to Fix It:

  • Create a custom AMI with all your tools, settings, and base config.
  • Use EC2 Image Builder to automate image creation and updates.
  • This dramatically speeds up provisioning and reduces setup errors.

Custom AMIs are like golden templates for repeatable, optimized deployments.

10. Skipping IAM Role Setup and Using Root Credentials

The Mistake:
Assigning your EC2 instance no role—or worse, hardcoding AWS credentials that belong to your root user.

What Happens:

  • Your app can’t access S3, DynamoDB, or other AWS services securely.
  • Leaked credentials lead to account compromise.
  • No way to apply least-privilege access control.

Real-World Pain:
You store AWS credentials in a .env file. One day, you accidentally git push it. Days later, you get billed for a crypto-mining farm you didn’t authorize.

How to Fix It:

  • Create a custom IAM role for your EC2 instance.
  • Attach it when launching the instance (or add it later).
  • Define fine-grained policies—only give the permissions the app needs.

This makes your app more secure and compliant, and reduces the risk of human error.

Final Thoughts

EC2 is incredibly powerful, but with that power comes responsibility. Most of the mistakes we covered above don’t come from ignorance—they come from being busy, under pressure, or not knowing what best practices look like until it’s too late.

Here’s a quick recap:

Mistake              Fix                                  
1. Security Groups   Open correct ports, limit IPs        
2. No Elastic IP     Allocate and attach one              
3. No Load Balancing Use ELB + Auto Scaling               
4. Data on Instance  Use S3, RDS, EFS                     
5. Hardcoded Secrets Use Parameter Store / Secrets Manager
6. No Monitoring     Set up CloudWatch and alerts         
7. No Updates        Automate patching                    
8. Manual Setup      Use Terraform or CloudFormation      
9. Default AMI       Build and reuse custom AMIs          
10. Root Credentials Use IAM roles with least privilege   

You don’t have to be a DevOps expert to deploy apps well on EC2. You just need a plan, a few tools, and an eye for detail.

You may also like:

  1. Top 10 Large Companies Using Node.js for Backend

  2. Why 85% of Developers Use Express.js Wrongly

  3. Top 10 Node.js Middleware for Efficient Coding

  4. 5 Key Differences: Worker Threads vs Child Processes in Node.js

  5. 5 Effective Caching Strategies for Node.js Applications

  6. 5 Mongoose Performance Mistakes That Slow Your App

  7. Building Your Own Mini Load Balancer in Node.js

  8. 7 Tips for Serverless Node.js API Deployment

  9. How to Host a Mongoose-Powered App on Fly.io

  10. The Real Reason Node.js Is So Fast

  11. 10 Must-Know Node.js Patterns for Application Growth

  12. How to Deploy a Dockerized Node.js App on Google Cloud Run

  13. Can Node.js Handle Millions of Users?

  14. How to Deploy a Node.js App on Vercel

  15. 6 Common Misconceptions About Node.js Event Loop

  16. 7 Common Garbage Collection Issues in Node.js

  17. How Do I Fix Performance Bottlenecks in Node.js?

  18. What Are the Advantages of Serverless Node.js Solutions?

  19. High-Traffic Node.js: Strategies for Success

Read more blogs from Here

Share your experiences in the comments, and let's discuss how to tackle them!

Follow me on LinkedIn

Top comments (1)

Collapse
 
nevodavid profile image
Nevo David

Pretty cool seeing all these gotchas in one place. I’ve wasted way too many hours chasing down silly config mistakes myself.